Programmierstyl

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.
Benutzeravatar
Domroon
User
Beiträge: 104
Registriert: Dienstag 3. November 2020, 10:27
Wohnort: Dortmund

Liebes Forum,

dies ist mein erster Post. Ich habe nun mein erstes Python-Programm geschrieben und möchte gerne Feedback von euch erhalten. Ist mein Programmierstyl gut so wie er ist oder kann ich bestimmte Sachen deutlich "schöner" machen? Ich freue mich über jede Kritik und Anmerkung.

Hier der Link zum Respository auf Github:
https://github.com/Domroon/RockPaperScissor

Ich hoffe der Link reicht aus. Wenn nicht, dann lasse ich mich gerne eines besseren belehren.
Das Spiel ist noch nicht ganz fertig aber schon lauffähig. Eine einzige Runde lässt sich damit schon spielen, was sich natürlich noch ändern soll. Auch ist eine Bestenliste geplant. Die Readme wird auch noch besser... Versprochen :D

Ich freue mich auf eure Beiträge.
Domroon
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

Am besten postet Du Code hier im Forum direkt in Code Tags (</>-Knopf).

Module schreibt man wie Variablen- oder Funktionsnamen komplett klein. Wenn ein Projekt mehr als ein Modul hat, packt man alles in ein Pakage.
Du hast aber eine Klasse pro Datei. Das macht man in Python nicht. Bei so einem kleinen Projekt würde man noch alles in eine Datei packen.

Auf oberster Ebene sollte kein ausführbarer Code stehen, daher gehören die beiden Zeilen in app.py in eine Funktion, die üblicherweise main genannt wird.

Code: Alles auswählen

def main():
    game = Game()
    game.round()

if __name__ == '__main__':
    main()
In User.py:
- man schreibt keine Trivialen Getter oder Setter.
- in set_choice hast Du dreimal den selben if-Block, nur die Bedingung ist unterschiedlich, also kann man das alles in eines zusammenfassen.
- wenn der einzige Fall, wo eine Exception auftritt, selbst erzeugt ist, dann würde ich ein normales if benutzen.
- andererseits sollte keine Fehlerbehandlung in solch einer Funktion stehen, so dass der ValueError gar nicht abgefangen werden sollte.

Code: Alles auswählen

class User:
    def __init__(self, name):
        self.score = 0
        self.name = name
        self.choice = "nothing"
        self.have_win = False

    def set_one_point(self):
        self.score += 1

    def set_choice(self, move):
        if move not in ["rock", "paper", "scissor"]:
            raise ValueError('You can choose between "rock", "paper" or "scissor"')
        self.choice = move
Fortgeschrittene würden choice als Property implementieren.

Bei Npc.py:
- keine Ahnung was Npc bedeuten soll. Benutze keine Abkürzungen, sondern sprechende Namen.
- bei randint: Benutze keine fixen Werten würde, sondern ermittle sie dynamisch aus der Länge der Liste, noch besser random.choice benutzen.
- move wäre besser eine Konstante.

Code: Alles auswählen

import random

class Npc:
    MOVE = [
        "rock",
        "paper",
        "scissor"
    ]
    def __init__(self):
        self.score = 0
        self.choice = "nothing"

    def set_one_point(self):
        self.score += 1

    def set_choice(self):
        self.choice = random.choice(self.MOVE)
In Game.py:
Du solltest auf Falscheingaben des Nutzers reagieren.
`is_winner` wird aufgerufen ohne dass man etwas mit dem Rückgabewert macht.
is_winner sollte alle Fälle abprüfen. So wie es jetzt da steht überrascht es den Leser, dass manche if-Zweige gar keinen Rückgabewert haben.

Code: Alles auswählen

import time

class Game:
    def __init__(self):
        self.user = User("Nobody")
        self.npc = Npc()

    def startcreen(self):
        print('Welcome to the Game "Rock, Paper or Scissor!"')
        self.user.name = input("Name: ")
        print(f"Hello {self.user.name}! Lets start the Game!")

    def round(self):
        # user and npc take their choices
        while True:
            try:
                self.user.set_choice(input("Please take your choice: "))
            except ValueError as error:
                print(error)
        self.npc.set_choice()
        self.round_animation()
        print(f"{self.user.choice} against {self.npc.choice}")
        winner = self.get_winner()
        if winner is None:
            print("Undecided!")
        else:
            winner.set_one_point()
            if winner is self.user:
                print("You win!")
            else:
                print("You loose!")
        print(f"User score: {self.user.score}")
        print(f"Npc score: {self.npc.score}")

    def round_animation(self):
        time.sleep(1)
        print("Rock!")
        time.sleep(1)
        print("Paper!")
        time.sleep(1)
        print("Scissor!")
        time.sleep(1)

    def get_winner(self):
        choice_user = self.user.choice
        choice_npc = self.npc.choice
        if choice_user == "rock":
            if choice_npc == "paper":
                return self.npc
            elif choice_npc == "scissor":
                return self.user
            else:
                return None
        elif choice_user == "paper":
            if choice_npc == "scissor":
                return self.npc
            elif choice_npc == "stone":
                return self.user
            else:
                return None
        elif choice_user == "scissor":
            if choice_npc == "rock":
                return self.npc
            elif choice_npc == "paper":
                return self.user
            else:
                return None
        else:
            raise ValueError()
Der Code ist im Moment noch unflexibler, als er sein müßte. Es wäre kein Problem, dass zwei Computer oder zwei Menschen gegeneinander spielen.
Dass so oft die Strings "scissor", "paper" und "rock" auftauchen, ist eine potentielle Fehlerquelle. Ein Enum ist die übliche Lösung dafür. Der Algorithmus würde auch deutlich einfacher, wenn man die Namen durch numerische Werte ersetzt.
startscreen wird nie aufgerufen.
have_win wird gar nicht benutzt. Und choice ist auch nicht wirklich ein Zustand der Klassen User und Npc sondern eher eine Methode: get_choice.
Benutzeravatar
Domroon
User
Beiträge: 104
Registriert: Dienstag 3. November 2020, 10:27
Wohnort: Dortmund

Hallo Sirirus3,

Vielen Dank für diese schnelle und umfangreiche Antwort :) Ich werde in Kürze Deine Verbesserungsvorschläge umsetzten und mich dann wieder melden ;)
Benutzeravatar
Domroon
User
Beiträge: 104
Registriert: Dienstag 3. November 2020, 10:27
Wohnort: Dortmund

Ich sehe ein, dass die natürlich kein großes Programm ist und diese Dateistrukturen wahrscheinlich übertrieben sind. Ehrlich gesagt möchte ich aber in die Zukunft schauen und meine Programme von vorn herein so schreiben wie man auch größere Programme schreiben würde. Vielen Dank für den Hinweis meine Module in Packages zu organisieren :) Die Modulnamen sind nun auch klein geschrieben. Wieso darf ich eine einzelne Klasse nicht in einer Datei schreiben? Ich finde das sehr übersichtlich und in vielen größeren Python-Projekten in Python ist es auch so organisiert. Gibt es einen anderen Grund dies nicht auf diese Art und Weise zu tun?


In user.py:
- ohne diese Trivialen Getter und Setter Dateien würde mein Programm nicht mehr funktionieren, wie soll ich denn stattdessen auf die Attribute des Objektes zugreifen?
- deine verbesserte version der "set_choice"-methode habe ich nun übernommen, vielen dank dafür
- fängt man die Fehler immer besser auf einer höheren ebene ab? In der game.py-klasse habe ich den Fehler nun in einer "höheren ebene" wie folgt abgefangen:

/<
# user and npc take their choices
while True:
try:
self.user.set_choice(input("Please take your choice: "))
break
except ValueError:
print('You can choose between "rock", "paper" or "scissor"')
/> (ich verstehe diese Codetags nicht :D)

In game.py:
- wie oben beschrieben reagiere ich nun auf falscheingaben, habe aber nun doch deine lösung für falscheingaben benutzt
narpfel
User
Beiträge: 645
Registriert: Freitag 20. Oktober 2017, 16:10

@Domroon: Auf die Attribute greift man zu, indem man auf die Attribute zugreift. :)

`set_one_point` ist ein unpassender Name, finde ich. Ich würde erwarten, dass die Methode `score` auf 1 setzt, nicht um 1 inkrementiert. `add_point` wäre passender.
Benutzeravatar
Domroon
User
Beiträge: 104
Registriert: Dienstag 3. November 2020, 10:27
Wohnort: Dortmund

@narpfel: Das macht Sinn :D Ich habe nur aus dem Informatikunterricht in der Schule gelernt (dort haben wir mit Java programmiert), dass man generell diese getter und setter- Methoden schreiben sollte und nicht direkt auf die attribute zugreifen sollte... Warum weiß ich nicht mehr :D Aber gut, dass es in Python einfacher ist ;) Gute Anregung, den Namen von "set_one_point" werde ich nun ändern :)

PS: Ich habe nun viele Anpassungen vorgenommen und meine erste Version released :P Schaut doch mal nochmal in mein Repository: https://github.com/Domroon/RockPaperScissor
narpfel
User
Beiträge: 645
Registriert: Freitag 20. Oktober 2017, 16:10

@Domroon: Python ist nicht Java. :)

In Java muss man Getter und Setter schreiben, wenn man sich die Möglichkeit offen halten möchte, ein Klasse später nochmal zu verändern, ohne den gesamten Code anzupassen, der die Klasse benutzt. Wenn du irgendwann merkst, dass du ein Attribut gar nicht brauchst (zum Beispiel, weil du es aus anderen Attributen berechnen kannst), musst du in Java alle Stellen ändern, wo das Attribut verwendet wird.

In Python wird mit dem Problem anders umgegangen: Erstens YAGNI. Zweitens gibt es `property`, mit dem man Getter und Setter quasi nachträglich einbauen kann, ohne vorsorglich den Code mit `get_foo` und `set_bar` unleserlich zu machen.
Benutzeravatar
Domroon
User
Beiträge: 104
Registriert: Dienstag 3. November 2020, 10:27
Wohnort: Dortmund

@narpfel, @Sirius3
Ich habe den Code nun so angepasst, dass ich alle (wie Sirius3 schon schrieb) trivialen getter und setter-Methoden gelöscht habe und nun mit "beispielobjekt.attribut" auf das jeweilige Attribut zugreife. Lediglich wo ein trivialer Zugriff nicht möglich ist habe ich das entsprechende Attribut von public auf private (mit dem Underscore "_"vor dem Attribut) geändert und mittels "@property" als getter oder setter methoden implementiert.
siehe z. B. hier in der User-Klasse:

Code: Alles auswählen


class User:

    def __init__(self, name):
        self.score = 0
        self.name = name
        self._choice = "nothing"
        self.have_win = False

    def add_point(self):
        self.score = self.score + 1

    @property
    def choice(self):
        return self._choice

    @choice.setter
    def choice(self, move):
        if move not in ["rock", "paper", "scissor"]:
            raise ValueError('You can choose between "rock", "paper" or "scissor"')
        self._choice = move

Ich habe also alle trivialen getter und setter gelöscht und nur dort wo es notwendig ist (notwendig heißt z. B. ein Wert für ein Attribut kommt z. B. vom Benutzer und es muss vorher geprüft werden ob dieser Wert ein gültiger ist) habe ich property benutzt
Meine FrageFragen: Habe ich den Sinn hinter property richtig verstanden oder habt ihr dem etwas hinzuzufügen oder zu korrigieren? Wäre property auch bei der Methode "add_point" sinnvoll?

Danke euch schonmal und schönen Tag euch ;)
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Man kann in Python auch von außerhalb der Klasse auf Variablen mit einem Unterstrich davor zugreifen. So etwas wie private exestiert nicht. Der Unterstrich ist eher eine Konvention, dass man die Variable nicht benutzen soll bzw. nicht drauf zugreifen soll.

Hier noch der Teil aus der Doku: hier
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

Ja, genauso kann man Properties benutzen.
Wie soll denn add_point zu einem property werden? Die Methode hat doch gar kein Argument, das gesetzt werden soll.
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

Aus dem Repository: in npc.py (immer noch ein schlechter Name und immer noch eine zu feingliedrige Aufteilung in Dateien) hast Du ein Property score, das eigentlich überflüssig ist. Auch choice ist hier kein Property.

Code: Alles auswählen

POSSIBLE_MOVES = ["rock", "paper", "scissor"]

class Npc:
    def __init__(self):
        self.score = 0
        self.choice = "nothing"

    def add_point(self):
        self.score += 1

    def make_choice(self):
        self.choice = random.choice(POSSIBLE_MOVES)
Und hier hast Du ja auch schon eine Liste mit möglichen Werten, die Du in User wiederverwenden solltest:

Code: Alles auswählen

class User:
    def __init__(self, name):
        self.score = 0
        self.name = name
        self._choice = "nothing"

    def add_point(self):
        self.score += 1

    @property
    def choice(self):
        return self._choice

    @choice.setter
    def choice(self, move):
        if move not in POSSIBLE_MOVES
            raise ValueError(f'You can choose between {" / ".join(POSSIBLE_MOVES)}')
        self._choice = move
Das zeigt auch schön, dass eine zu starke Aufteilung in Dateien es schwierig macht, gemeinsame Daten zu nutzen.
Wie schon in meinem ersten Post geschrieben, macht das unterschiedliche Interface von User und Npc es schwierig, die beiden einfach auszutauschen, was den schönen Effekt hätte, dass man wählen könnte ob zwei Personen oder zwei Computer gegeneinander spielen.

In app.py wird jetzt ein Design-Problem noch deutlicher: du erzeugst einen User mit Dummy-Namen, dem Du erst viel später an ganz anderer Stelle einen richtigen Namen gibst. Das macht das Programm sehr unübersichtlich und fehleranfällig: wie heißt der User wirklich? Wo wird da was geändert, und wird das überhaupt immer geändert? Ein Grundsatz ist: benutze niemals Dummy-Werte. Verwende von Anfang an den richtigen Wert für eine Variable. Es gibt Fälle, wo explizit erlaubt ist, dass eine Variable auch "keinen Wert" haben kann, das ist dann None; das muß aber auch explizit an jeder Stelle mit berücksichtigt werden. Hier ist das aber nicht der Fall.
`max_score` wird gar nicht berücksichtigt; hier ist einer der Fälle, wo eine while-True-Schleife falsch eingesetzt wird (normalerweise ist es immer umgekehrt).

Code: Alles auswählen

MAX_SCORE = 3

def main():
    print('Welcome to the Game "Rock , Paper or Scissor!"')
    name = input("Name: ")
    print(f"Hello {name}! Lets start the Game!")
    user = User(name)
    npc = Npc()
    game = Game(user, npc)
    while user.score < MAX_SCORE and npc.score < MAX_SCORE:
        game.round()
    print("Thank you for gaming!")

if __name__ == '__main__':
    main()
Benutzeravatar
Domroon
User
Beiträge: 104
Registriert: Dienstag 3. November 2020, 10:27
Wohnort: Dortmund

@Jankie:
achso, gut zu wissen, vielen Dank für diese Anmerkung :)

@Sirius3:
Ich will parallel mit git und github warm werden. Deshalb habe ich einen neuen Branch "Sirius3_deep_improvements" erstellt.
Ich möchte hier kurz die letzten commits schreiben, ich hoffe das ist ok für alle
(ich buchstabiere diese durch um eine Frage zum jeweiligen commit zu stellen):

a- rename npc to computer
b- delete computer.py-, game.py-, user.py - files and put them all in app.py
c- delete unnecessary files
d- put POSSIBLE_MOVES outside from Computer-class
e- improve the main-method

zu a:
Völlig verständlich.

zu b:
Okay ich verstehe den Sinn, dass die Klassen in eine gemeinsame Datei gepackt werden sollten. Klar so ist es einfacher gemeinsame Daten zu nutzen. Nur jetzt muss ich immer hoch und runter scrollen nur um zu gucken welche Methoden in der jeweiligen Klasse zu Verfügung stehen. Das Projekt ist klein. Aber gehen wir mal davon aus, dass das Programm jetzt immer weiter wächst: Wäre es dann ab einem bestimmten Punkt sinnvoll die Klassen in eigene Dateien zu packen oder wie würde man dann vorgehen?

zu d:
Ist klar

zu d: Ich bin verwirrt. Ich hatte schon ein wenig mit C++ und Java zu tun. Dort war es gefühlt immer eine Todessünde wenn man eine globale Variable erstellt hat. Warum macht man das hier in Python anders? Oder bin ich gerade auf einem völlig falschen Zug?

zu e:
Versteh ich glaube ich ;)

Hier der aktuelle Code von Github, welcher nur noch aus der Datei app.py besteht:

Code: Alles auswählen

import random
import time

POSSIBLE_MOVES = ["rock", "paper", "scissor"]
MAX_SCORE = 3


class Game:
    def __init__(self, user, computer):
        self.user = user
        self.computer = computer

    def round(self):
        # user and computer take their choices
        while True:
            try:
                self.user.choice = input("Please take your choice: ")
                break
            except ValueError as error:
                print(error)
        self.computer.make_choice()
        self.round_animation()
        print(f"{self.user.choice} against {self.computer.choice}")
        winner = self.get_winner()
        if winner is None:
            print("Undecided!")
        else:
            winner.add_point()
            if winner is self.user:
                print("You win!")
            else:
                print("You loose!")
        print(f"User score: {self.user.score}")
        print(f"computer score: {self.computer.score}")

    def round_animation(self):
        speed = 0.5
        time.sleep(speed)
        print("Rock!")
        time.sleep(speed)
        print("Paper!")
        time.sleep(speed)
        print("Scissor!")
        time.sleep(speed)

    def get_winner(self):
        choice_user = self.user.choice
        choice_computer = self.computer.choice
        if choice_user == "rock":
            if choice_computer == "paper":
                return self.computer
            elif choice_computer == "scissor":
                return self.user
            else:
                return None
        elif choice_user == "paper":
            if choice_computer == "scissor":
                return self.computer
            elif choice_computer == "rock":
                return self.user
            else:
                return None
        elif choice_user == "scissor":
            if choice_computer == "rock":
                return self.computer
            elif choice_computer == "paper":
                return self.user
            else:
                return None
        else:
            raise ValueError()


class User:

    def __init__(self, name):
        self.score = 0
        self.name = name
        self._choice = "nothing"
        self.have_win = False

    def add_point(self):
        self.score += 1

    @property
    def choice(self):
        return self._choice

    @choice.setter
    def choice(self, move):
        if move not in POSSIBLE_MOVES:
            raise ValueError(f'You can choose between {" / ".join(POSSIBLE_MOVES)}')
        self._choice = move


class Computer:
    def __init__(self):
        self.score = 0
        self.choice = "nothing"

    def add_point(self):
        self.score = self.score + 1

    def make_choice(self):
        self.choice = random.choice(POSSIBLE_MOVES)


def main():
    print('Welcome to the Game "Rock, Paper or Scissor!"')
    name = input("Name: ")
    print(f"Hello {name}! Lets start the Game!")
    user = User(name)
    computer = Computer()
    game = Game(user, computer)
    while user.score < MAX_SCORE and computer.score < MAX_SCORE:
        game.round()
    print("Thank you for gaming!")


if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

zu b) natürlich wird eine Datei irgendwann zu groß. Wobei man darauf achten sollte, dass man thematisch trennt, so dass man möglichst wenig Abhängigkeiten zwischen den Dateien hat und vor allem nur in eine Richtung. Ringabhängigkeiten sind zu vermeiden.
zu d) wo sind denn da globale Variablen? Bei POSSIBLE_MOVES sieht man doch schon an der Schreibweise, dass das eine Konstante ist.
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei das mit dem Hoch- und Runterscrollen bei modernen Editoren nicht wirklich eine Begründung ist. Wenn ein Editor keine Baumdarstllung der Struktur und/oder „folding“ beherrscht wo man alles bis auf die Klassen und Funktions- und Methodensignaturen ausblenden kann, sollte man sich nach einem anderen Editor beziehungsweise einer anderen IDE umschauen.

Und das Problem verschwindet doch auch überhaupt nicht wenn man jede Klasse in eine eigene Datei stecken‽ Dann muss man ja sogar die Datei wechseln wenn man Methoden in anderen Klassen sehen will, wenn die in anderen Dateien stecken.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Domroon
User
Beiträge: 104
Registriert: Dienstag 3. November 2020, 10:27
Wohnort: Dortmund

@Sirius3:
zu b:
Das klingt sinnvoll. Was genau meinst Du mit Abhängigkeiten bzw. Ringabhängigkeiten? Ich kann mir leider nicht vorstellen wie das gemeint ist. Kannst Du mir ein Beispiel nennen oder einen Link schicken, damit mir das klarer wird?

zu d:
Ups, mein Fehler.

@__blackjack__:
Ich benutze PyCharm. Jetzt wo du es sagst, erscheinen mir die "Pluszeichen" links zum folden sehr sinnvoll ;) Eine Baumdarstellung habe ich allerdings noch nicht entdeckt. Die finde ich aber sicherlich noch irgendwo ;)

Danke auf jedenfall an alle die sich hier so viel Mühe geben ;)
narpfel
User
Beiträge: 645
Registriert: Freitag 20. Oktober 2017, 16:10

@Domroon: Ein Ringabhängigkeit (circular dependency) ist, wenn zwei Module sich gegenseitig importieren. Das ist in Python problematisch, weil der Code von oben nach unten abgearbeitet wird. Beispiel:

Code: Alles auswählen

# foo.py
from bar import bar

ANSWER = 42

def foo():
    print(bar())

Code: Alles auswählen

# bar.py
from foo import ANSWER

def bar():
    return ANSWER

Code: Alles auswählen

# main.py
from foo import foo

if __name__ == "__main__":
    foo()

Code: Alles auswählen

» python main.py
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    from foo import foo
  File "/tmp/t/foo.py", line 2, in <module>
    from bar import bar
  File "/tmp/t/bar.py", line 2, in <module>
    from foo import ANSWER
ImportError: cannot import name 'ANSWER' from partially initialized module 'foo' (most likely due to a circular import) (/tmp/t/foo.py)
Wenn `bar` importiert wird, wird `from foo import ANSWER` ausgeführt, aber `ANSWER` ist in `foo` noch gar nicht definiert worden.
Benutzeravatar
Domroon
User
Beiträge: 104
Registriert: Dienstag 3. November 2020, 10:27
Wohnort: Dortmund

@narpfel: ah okay, danke für das Beispiel, ich habs verstanden ;)
Benutzeravatar
Domroon
User
Beiträge: 104
Registriert: Dienstag 3. November 2020, 10:27
Wohnort: Dortmund

Hallo nochmal,
ich bin gerade dabei die User-Klasse zu erweitern.
Es soll nun möglich sein einem User ein Passwort zuzuweisen. Zunächst wird die passwort-länge überprüft bevor der eingegebene String dem passwort-attribut zugewiesen wird. Hier die wichtigen Code-stellen aus meinem Repository (https://github.com/Domroon/RockPaperScissor) :

Code: Alles auswählen

PASSWORD_LENGTH = 8

class User:

    def __init__(self, name):
        self.score = 0
        self.name = name
        self._password = None
        self._choice = "nothing"

    def add_point(self):
        self.score += 1

    @property
    def choice(self):
        return self._choice

    @choice.setter
    def choice(self, move):
        if move not in POSSIBLE_MOVES:
            raise ValueError(f'You can choose between {" / ".join(POSSIBLE_MOVES)}')
        self._choice = move

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, password):
        # password needs:
        # letter in upper and lower case
        # at least one special sign
        # at least one number
        if len(password) >= 8:
            self._password = password
        else:
            raise ValueError("Password needs at least 8 character")
           
 def test():
    user = User("Max")
    try:
        user.password = "asdf"
    except ValueError as err:
        print(err)

    if user.password is None:
        print("User password is incorrect")
    else:
        print("You can use this password")


def main():
    test()
    '''
    print('Welcome to the Game "Rock, Paper or Scissor!"')
    name = input("Name: ")
    print(f"Hello {name}! Lets start the Game!")
    user = User(name)
    computer = Computer()
    game = Game(user, computer)
    while user.score < MAX_SCORE and computer.score < MAX_SCORE:
        game.round()
    print("Thank you for gaming!")
    '''

if __name__ == '__main__':
    main()
Ich finde es unschön wie ich hier das passwort zuweise. In der Initialisierungsmethode weise ich dem passwort-attribut zunächst "None" zu da ich es nicht anders hinbekommen habe.
Meine Frage: Ist es möglich die passwort-setter-methode in der init-methode irgendwie aufzurufen, damit die user-klasse direkt immer mit "password" initialisiert wird? Gut, ich kann bei der initialisierungsmethode "password" mit übergeben aber dann wird dieses ja nicht durch meine password-setter-methode überprüft ob dies überhaupt ein gültiges passwort ist :(
Ich stecke in der Zwickmühle..

Danke euch schonmal im vorraus ;)
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie kommst du drauf, dass die Passwortlänge nicht geprüft werden würde?
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Domroon: Zeichenketten sind keine Kommentare, die sollte man nicht zum auskommentieren von Code verwenden. Das Kommentarzeichen in Python ist #, und nur das.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten