Variablennamen auf str und int zusammensetzen

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.
sofasurfer0815
User
Beiträge: 14
Registriert: Sonntag 22. Juli 2018, 11:06

Hallo liebe Community,

Ich habe mir eine anfängertaugliche Aufgabe gestellt: Ich möchte ein Programm entwickeln, das den Spielstand bei einem Kartenspiel (Schafkopf) errechnet und fortschreibt. Im Prinzip funktioniert schon alles, aber jetzt möchte ich - bevor ich mich um die GUI kümmere - den Code "schöner" machen.

Ich habe eine Klasse "Spieler" definiert:

Code: Alles auswählen

class Spieler:

    def __init__(self, name, konto):
        self.name = name
        self.konto = konto
Dazu gibt es zwei für mein Problem eine relevante Funktion:

Code: Alles auswählen

    def print_spielstand(self):
        print(self.name, ": ", self.konto)
Im folgenden zwei Beispiele, wie ich einen Spielernamen mit Initialkontostand "0" anlege und den Kontostand auslese:

Erstes Beipiel (funktioniert):

Code: Alles auswählen

            s1 = Spieler((input ("Spieler 1: ")), 0)
            s2 = Spieler((input ("Spieler 2: ")), 0)
            s3 = Spieler((input ("Spieler 3: ")), 0)
            s4 = Spieler((input ("Spieler 4: ")), 0)

Code: Alles auswählen

            s1.print_spielstand()
            s2.print_spielstand()
            s3.print_spielstand()
            s4.print_spielstand()
Zweites Beispiel (wahrscheinlich eleganter, aber funktioniert nicht):

Code: Alles auswählen

           for i in range (1,5):
                var: str = 's' + str(i)
                var = Spieler((input ("Spieler " + str(i) + ": ")), 0)

Code: Alles auswählen

            for i in range (1,5):
                var: str = 's' + str(i)
                var.print_spielstand()
Ist meine zweite Lösung wirklich "schöner" als die erste? Warum funktioniert sie nicht?

Ergebnis der 2. Lösung: Bei der Eingabe der Namen keine Fehlermeldung, aber bei der Ausgabe:

===========
Traceback (most recent call last):
File "C:/Users/julian/PycharmProjects/Schafkopfrechner/Schafkopfrechner.py", line 166, in <module>
main()
File "C:/Users/julian/PycharmProjects/Schafkopfrechner/Schafkopfrechner.py", line 159, in main
var.print_spielstand()
AttributeError: 'str' object has no attribute 'print_spielstand'

Bin um jede Hilfe dankbar.
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

Die Syntax, die du im zweiten Beispiel verwendest, ("var: ...") gibt es in Python nicht. Wo hast du das her? Statt durchnummerierter Variablen nimmt man entweder eine Liste, oder für manche Anwendungszwecke auch ein Wörterbuch.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

sofasurfer0815 hat geschrieben: Sonntag 22. Juli 2018, 11:22 Zweites Beispiel (wahrscheinlich eleganter, aber funktioniert nicht):

Code: Alles auswählen

           for i in range (1,5):
                var: str = 's' + str(i)
                var = Spieler((input ("Spieler " + str(i) + ": ")), 0)

           for i in range (1,5):
                var: str = 's' + str(i)
                var.print_spielstand()
Da sind warum auch immer Doppelpunkte im Code?
Und eine Variable so zu nennen wie eine definierte Funktion in Python ist nicht gut str = ..... + str(...)
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Die Variable heisst `var` und hat die Typinformation `str`. Das stimmt schon so. Obwohl es natürlich Unsinn ist einen Typ der so offensichtlich ist zu annotieren. Typannotation ist Scheisse!

Edit: Wobei es in der ersten Schleife ja auch nicht stimmt, denn da wird dann ja an den Namen `var` die als `str` annotiert wurde, gleich in der nächsten Zeile etwas vom Typ `Spieler` gebunden. Da weist die Typprüfung die man bei Code mit Typannotationen macht, doch eigentlich drauf hin? Warum wurde das hier nicht als Fehlermeldung erwähnt? Weil keine Typprüfung gemacht wurde? Warum dann Typannotationen? :evil:
Zuletzt geändert von __blackjack__ am Sonntag 22. Juli 2018, 11:48, insgesamt 1-mal geändert.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

__blackjack__ hat geschrieben: Sonntag 22. Juli 2018, 11:44 Die Variable heisst `var` und hat die Typinformation `str`. Das stimmt schon so. Obwohl es natürlich Unsinn ist einen Typ der so offensichtlich ist zu annotieren. Typannotation ist Scheisse!
OMG, darauf bin ich gar nicht gekommen, ich dachte das ist Java oder ein anderer Mischmasch.
Stimme dir zu 100% zu.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Statt zu versuchen, Variablennamen durchzunummerieren, nimmt man statt dessen Listen:

Code: Alles auswählen

class Spieler:
    def __init__(self, name, konto):
        self.name = name
        self.konto = konto

    def __str__(self):
        return "{}: {}".format(self.name, self.konto)


def input_players(count):
    result = []
    for n in range(1, count + 1):
        name = input("Spieler {}:".format(n))
        result.append(Spieler(name, 0))


players = input_players(4)
for player in players:
    print(player)
sofasurfer0815
User
Beiträge: 14
Registriert: Sonntag 22. Juli 2018, 11:06

Hallo,

danke für die schnelle Antwort.
Das var: kommt - glaube ich - von einem Vorschlag der IDE. Das mit der Variable "str" ist auch nicht geschickt.

Hier die Korrektur:

Code: Alles auswählen

            for i in range (1,5):
                sp = 's' + str(i)
                sp = Spieler((input ("Spieler " + str(i) + ": ")), 0)

Code: Alles auswählen

            for i in range (1,5):
                sp = 's' + str(i)
                sp.print_spielstand()
Ich baekomme den Fehler:
sp.print_spielstand()
AttributeError: 'str' object has no attribute 'print_spielstand'

Ich nehme an, dass die Zeile sp = 's' + str(i) nicht funktioniert.

Folgendes funktioniert aber in IDLE:

>>> i = 1
>>> sp = 's' + str(i)
>>> print (sp)
s1
>>>

Wo stehe ich auf dem Schlauch?
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

du gehst nicht auf das ein was Sirius3 geschrieben hat.
Deine Variable sp ist vom Typ string und der hat keine Methode print_spielstand()
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@sofasurfer0815: das kann auch nicht Funktionieren, weil ein String etwas anderes ist als eine Spieler-Instanz. Statt also etwas zu versuchen, was nicht funktioniert, nimm die Lösung, die ich Dir gezeigt habe.
sofasurfer0815
User
Beiträge: 14
Registriert: Sonntag 22. Juli 2018, 11:06

Danke, Sirius3!
Ich habe keinen "refresh" gemacht und deine Antwort jetzt erst gesehen.
Ich melde mich gleich wieder ...
sofasurfer0815
User
Beiträge: 14
Registriert: Sonntag 22. Juli 2018, 11:06

Hallo,
mein Code sieht jetzt nach den Verbesserungen von Sirius 3 so aus:

Code: Alles auswählen

class Spieler:

    def __init__(self, name, konto):
        self.name = name
        self.konto = konto

    def __str__(self):
        return "{}: {}".format(self.name, self.konto)

    def input_players(count):
        result = []
        for n in range(1, count + 1):
            name = input("Spieler {}:".format(n))
            result.append(Spieler(name, 0))

Code: Alles auswählen

def main():
    while True:

        print("(1) Namen eingeben - (2) Spiel eingeben - (3) Spielstand anzeigen")
        auswahl = input()

        if auswahl == "1":  # Eingabe Spielernamen
            print("Eingabe Spielernamen:")
            print("=====================")
            players = Spieler.input_players(4)
[...]

Code: Alles auswählen

       elif auswahl == "3":

            print("Spielstand:")
            print("===========")
            for player in players:
                print(player)
Für die vorletzte Zeile bekomme ich den Fehler:
TypeError: 'NoneType' object is not iterable

Ich glaube ich habe mir als Anfängerprojekt zu viel vorgenommen...
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@sofasurfer0815: `players` ist `None` weil `input_players()` nichts zurück gibt, und das bedeutet in Python das implizit `None` zurückgegeben wird. Du musst das `result` da schon an den Aufrufer zurückgeben. Die Funktion gehört auch nicht in die Klasse oder falls Du sie dort haben möchtest, sollte sie mit `@staticmethod` dekoriert werden, damit der Leser weiss, dass das Absicht ist eine Funktion in die Klasse zu stecken.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
sofasurfer0815
User
Beiträge: 14
Registriert: Sonntag 22. Juli 2018, 11:06

Das verstehe ich nicht. Ich habe zur Laufzeit ja mit "input_players" die Spieler eingegeben.

Hier mal mein gesamter Code:

Code: Alles auswählen

class Spieler:

    def __init__(self, name, konto):
        self.name = name
        self.konto = konto

    def __str__(self):
        return "{}: {}".format(self.name, self.konto)

    def input_players(count):
        result = []
        for n in range(1, count + 1):
            name = input("Spieler {}:".format(n))
            result.append(Spieler(name, 0))


        # Funktionrn für 'Spieler'

    def print_info(self):
        print("Spieler: ", self.nummer)
        print("Name: ", self.name)
        print("Spielstand: ", self.konto)

    def print_name(self):
        print(self.name)

    def print_spielstand(self):
        print(self.name, ": ", self.konto)

    def change_konto(self, spielart, spielwert, gvwert):

        if spielart == "sau":
            if gvwert == "g":
                self.konto += spielwert
            if gvwert == "v":
                self.konto -= spielwert
        if spielart == "solo":
            if gvwert == "g":
                self.konto += 3 * spielwert
            if gvwert == "v":
                self.konto -= spielwert

    def edit_spielstand(self, konto):
        print("Spielstand aktuell:")
        for i in range (1, 5):
            print(s + str(i).name)

def spielwert_berechnen(spielart, laeufer, schneider, leger):
    if spielart == "solo":  # Spielart -> Grundwert
        grundwert = 50
    elif spielart == "sau":
        grundwert = 20
    print("Grundwert: ", grundwert)
    if laeufer == "0":
        wertnachlaeufer = grundwert
    elif laeufer == "1":
        wertnachlaeufer = grundwert + 10
    elif laeufer == "2":
        wertnachlaeufer = grundwert + 20
    elif laeufer == "3":
        wertnachlaeufer = grundwert + 30
    elif laeufer == "4":
        wertnachlaeufer = grundwert + 40
    print(laeufer, "Laeufer: ", wertnachlaeufer)
    if schneider == "nein":
        wertnachschneider = wertnachlaeufer
    elif schneider == "ja":
        wertnachschneider = wertnachlaeufer + 10
    elif schneider == "schwarz":
        wertnachschneider = wertnachlaeufer + 20
        print("Schneider ", schneider, ": ", wertnachschneider)
    if leger == "0":
        wertnachleger = wertnachschneider
    elif leger == "1":
        wertnachleger = wertnachschneider * 2
    elif leger == "2":
        wertnachleger = (wertnachschneider * 2) * 2
    elif leger == "3":
        wertnachleger = ((wertnachschneider * 2) * 2) * 2
    elif leger == "4":
        wertnachleger = (((wertnachschneider * 2) * 2) * 2) * 2
    print(leger, " Leger")
    spielwert = wertnachleger
    return spielwert



def main():
    while True:

        print("(1) Namen eingeben - (2) Spiel eingeben - (3) Spielstand anzeigen")
        auswahl = input()

        if auswahl == "1":  # Eingabe Spielernamen
            print("Eingabe Spielernamen:")
            print("=====================")
            players = Spieler.input_players(4)


        elif auswahl == "2":  # Eingabe Spiel
            print("Eingabe Spiel:")
            print("==============")

            antwortspielart = input("(1) Sauspiel - (2) Solo/Wenz")  # Abfrage Spielwerte

            print("(g) gewonnen - (v) verloren")  # Wer hat gewonnen/verloren?

            s1.print_name()
            input(gvwert_s1)

            s2.print_name()
            input(gvwert_s1)

            s3.print_name()
            input(gvwert_s1)

            s4.print_name()
            input(gvwert_s1)


                
            if antwortspielart == "1":
                spielart = "sau"

            elif antwortspielart == "2":
                spielart = "solo"

            antwortleger = input("Anzahl Leger: ")

            antwortschneider = input("Schneider: (1) nein - (2) ja - (3) schwarz")

            if antwortschneider == "1":
                transschneider = "nein"

            elif antwortschneider == "2":
                transschneider = "ja"

            elif antwortschneider == "3":
                transschneider = "schwarz"

            antwortlaeufer = input("Anzahl Laeufer: ")

            spielwert = spielwert_berechnen(spielart, antwortlaeufer, transschneider, antwortleger)

            print("Spielwert: ", spielwert)

            for i in range (1, 5):
                s + str(i).change_konto(spielart, spielwert, gvwert_s+ 'i')

            print("Spielstand:")
            print("===========")
            for i in range (1, 5):
                Spieler.print_spielstand()

        elif auswahl == "3":

            print("Spielstand:")
            print("===========")
            for player in players:
                print(player)

            # s2.print_spielstand()
            # s3.print_spielstand()
            # s4.print_spielstand()

if __name__ == "__main__":
    main()
sofasurfer0815
User
Beiträge: 14
Registriert: Sonntag 22. Juli 2018, 11:06

PS: Ich weiss, auch hier ist noch eine Schleife drin, die ich durch eine Liste ersetzen sollte.
Der Fehler ist reproduzierbar, wenn man das Programm laufen lässt und zuerst unter "1" die Spielernamen eingibt und dann unter "3" anzeigen lässt.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Warum denkst Du denn das `players` einen anderen Wert als `None` haben sollte? Welche Zeile ist dafür verantwortlich?
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
sofasurfer0815
User
Beiträge: 14
Registriert: Sonntag 22. Juli 2018, 11:06

Folgende Zeile habe ich in Verdacht:
players = Spieler.input_players(4)
sofasurfer0815
User
Beiträge: 14
Registriert: Sonntag 22. Juli 2018, 11:06

bzw. die dadurch aufgerufene Funktion:

def input_players(count):
result = []
for n in range(1, count + 1):
name = input("Spieler {}:".format(n))
result.append(Spieler(name, 0))
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

dafür müsste aber die Methode input_players etwas mit der Liste die du eingibst machen
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Und wo steht in dieser Funktion was zurückgegeben werden soll? Du hast das doch in anderen Funktionen/Methoden bereits richtig gemacht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
sofasurfer0815
User
Beiträge: 14
Registriert: Sonntag 22. Juli 2018, 11:06

Ich glaube, ich weiß, worauf du hinaus willst...

Aber: result.append(Spieler(name, 0)) legt mir doch einen Spieler an.

z.B: den Spieler "__blackjack__" mit dem Kontostand "0",
wenn ich das so in bei der Funktion eingebe, oder nicht?
Antworten