Seite 1 von 1

Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 14:49
von UnSpeed
Hey Leute,

ich bin noch relativ neu mit Python zugange, allerdings nicht mit Programmierung an sich, deshalb macht mich auch das folgende Problem ein bisschen stutzig:

Code: Alles auswählen

import sys, random

def menue():
	level_int = 5
	spielen = True
	while spielen:
		print "(N)eues Spiel\n(L)evelauswahl\n(A)nleitung\n(B)eenden"
		eingabe = str(raw_input(""))
		if eingabe == "n" or eingabe == "N":
			#Hier beginnt ein neues Spiel
			print level_int
			zahl = random.randint(0,level_int*10)
			print zahl
		elif eingabe == "l" or eingabe == "L":
			#Hier kommt die Levelauswahl
			print "Es gibt drei Level:\n(L)eicht\n(M)ittel\n(S)chwer"
			level = str(raw_input(""))
			if level == "l" or eingabe == "L":
				level_int = 1
			elif level == "m" or eingabe == "M":
				level_int = 5
			elif level == "s" or eingabe == "S":
				level_int = 10
			else:
				print "Fehlerhafte Eingabe. Gehe zu Hauptmenue"
			print level_int
			menue()
		elif eingabe == "a" or eingabe == "A":
			#Hier kommt die Anleitung
			print ""
		elif eingabe == "b" or eingabe == "B":
			#Hier wird das Spiel beendet
			spielen = False
		

print "Hallo hier ein kleines Spiel :D"
menue()
Wenn ich jetzt das Programm starte, dann funktioniert auch eigentlich alles, bis auf die Tatsache, dass egal was ich in der Levelauswahl eingebe level_int bei einem neuen Spiel immer 5 wird.
Denn wenn ich beispielsweise als Level "(L)eicht" auswähle, dann wird level_int auf 1 gesetzt. Starte ich aber danach ein neues Spiel, dann ich level_int wieder automatisch 5...

Syntaxfehler sind keine vorhanden und den Logikfehler sehe ich nicht -.-

Bitte helft mich weiter, ich verzweifel sonst noch :D

Danke,
UnSpeed

Re: Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 15:45
von mutetella
Hallo,

nun ja, sobald 'menue()' aufgerufen wird, wird 'level_int' auf 5 gesetzt.

Es dürfte auch kaum möglich sein, das Spiel über b/B zu beenden... :wink:

Noch ein Tipp zur Vereinfachung: Statt

Code: Alles auswählen

eingabe == 'b' or eingabe == 'B'
würde ich die entweder die eingabe gleich in einen Klein- oder Großbuchstaben umwandeln

Code: Alles auswählen

#entweder
eingabe = str(raw_input('Diese Eingabe wird klein: ')).lower()
#oder
eingabe = str(raw_input('Diese Eingabe wird GROSS: ')).upper()
dann musst Du nur auf einen Groß- oder eben einen Kleinbuchstaben prüfen, oder aber Du überprüfst die Eingabe so:

Code: Alles auswählen

eingabe in 'aA'
mutetella

Re: Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 15:54
von UnSpeed
Mir ist bewusst, dass das beim Aufrufen der Funktion auf 5 gesetzt wird, aber die Variable wird ja innerhalb der Funktion geändert, und DAS ist meine Frage: WARUM ändert sich das trotzdem in 5?

Das mit der eingabe war auch nur eine Notlösung, denn der Befehl .lower() war mir bereits bekannt. Der Befehl in 'aA' da gegen nicht, danke ;)

Und doch, das Spiel lässt sich über b/B beenden, was ja auch logisch ist, weil dadurch die While-Schleife unterbrochen wird, die Funktion normal ausläuft und nach dem Funktionsaufruf nichts mehr folgt.


Leider weiß ich jetzt aber immer noch nicht, wie ich das eigentliche Problem beheben kann...

Re: Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 16:06
von mutetella
UnSpeed hat geschrieben:Und doch, das Spiel lässt sich über b/B beenden, ...
Stimmt. Mein Fehler, ich dachte, nach Eingabe von b/B geschieht dasselbe wie nach Eingabe von l/L, wo eben Dein Fehler steckt.
Damit meine ich, dass Du nach Eingabe von l/L die 'menue()' von neuem aufrufst und somit nicht zurück zum Schleifenanfang gehst, sondern eine neue Schleife startest. Mit anderen Worten:

Code: Alles auswählen

def menue():
    ...
    level = 5
    while spielen:
        ...
        if eingabe in 'lL':
            ...
            menue()
Da kannst Du l/L's auswählen, bis Du schwarz wirst oder irgendwann ein RuntimeError kommt, weil die maximale Rekursionstiefe erreicht ist.

Jetzt klarer?

mutetella

Re: Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 16:12
von UnSpeed
autsch xD

Allerdings, wenn ich den Code folgend umstelle, dann kann ich offenbar nicht auf die Variable "spielen" zugreifen:

Code: Alles auswählen

import sys, random

level_int = 5
spielen = True

def menue():
	while spielen:
		print "(N)eues Spiel\n(L)evelauswahl\n(A)nleitung\n(B)eenden"
		eingabe = str(raw_input(""))
		if eingabe == "n" or eingabe == "N":
			#Hier beginnt ein neues Spiel
			print level_int
			zahl = random.randint(0,level_int*10)
			print zahl
		elif eingabe == "l" or eingabe == "L":
			#Hier kommt die Levelauswahl
			print "Es gibt drei Level:\n(L)eicht\n(M)ittel\n(S)chwer"
			level = str(raw_input(""))
			if level == "l" or eingabe == "L":
				level_int = 1
			elif level == "m" or eingabe == "M":
				level_int = 5
			elif level == "s" or eingabe == "S":
				level_int = 10
			else:
				print "Fehlerhafte Eingabe. Gehe zu Hauptmenue"
			print level_int
			menue()
		elif eingabe == "a" or eingabe == "A":
			#Hier kommt die Anleitung
			print ""
		elif eingabe == "b" or eingabe == "B":
			#Hier wird das Spiel beendet
			spielen = False
		

print "Hallo hier ein kleines Spiel :D"
menue()
Dann kommt diese Fehlermeldung:

Traceback (most recent call last):
File "ratespiel.py", line 37, in <module>
menue()
File "ratespiel.py", line 5, in menue
while spielen:
UnboundLocalError: local variable 'spielen' referenced before assignment

Edit:
Hat sich erledigt, ich habe einfach die Variablen wieder reingetan und den Funktionsaufruf innerhalb der Funktion gelöscht.
Allerdings verstehe ich dir oben genannte Fehlermeldung noch nicht ganz...
Kann da vllt. bitte noch mal jmd. helfen?

Re: Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 16:42
von mutetella
Du denkst in die falsche Richtung... :wink:

Die Frage ist doch, weshalb muss denn 'menue()' neu aufgerufen werden? Du befindest Dich doch in einer Schleife...
Das was Du machst nennt sich Rekursion, das heißt, eine Funktion ruft sich selbst auf. Macht man z. B. bei Sortieralgorithmen.
Du möchtest aber etwas ganz anderes, nämlich nach der Levelauswahl wieder zurück zur Eingabe. Und um zur Eingabe zurückzukehren musst Du doch nicht erneut 'menue()' aufrufen.

mutetella

Re: Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 17:17
von mutetella
UnSpeed hat geschrieben:Allerdings verstehe ich dir oben genannte Fehlermeldung noch nicht ganz...
Das liegt daran, dass der Name 'spielen' außerhalb der Funktion 'menue()' erstellt wurde und daher innerhalb von 'menue()' nicht gesehen werden kann.
Wenn du innerhalb einer Funktion auf Namen zugreifen möchtest, die außerhalb erstellt wurden, dann musst Du diese Namen an die Funktion übergeben. In Deinem Fall könnte das so aussehen:

Code: Alles auswählen

import sys, random

level = 5
spielen = True

def menue(level, spielen):
    ...

menue(level, spielen)
Dabei geschieht folgendes: In dem Modul, in dem sich 'menue()' befindet, wird 'level' an die Zahl 5 und 'spielen' an den Wert True gebunden.
Durch den Aufruf von 'menue(level, spielen)' wird die Zahl 5 und der Wert True an die Funktion 'menue()' übergeben und dort an die Namen 'level' und 'spielen' gebunden. Wenn Du nun innerhalb der Funktion die Werte von 'level' oder 'spielen' änderst, gilt das auch nur innerhalb der Funktion, auf Modulebene bleibt alles beim alten. Auch wenn das nicht ganz korrekt ist kann man sagen, dass die Namen 'level' und 'spielen' doppelt existieren, einmal auf Modul- und einmal auf Funktionsebene.
Wenn Du 'level' und 'spielen' auch auf Modulebene an die Werte, die innerhalb der Funktion gelten, angleichen möchtest, könntest Du das z. b. so erreichen:

Code: Alles auswählen

import sys, random

level = 5
spielen = True

def menue(level, spielen):
    ...
    return (level, spielen)

level, spielen = menue(level, spielen)
mutetella

Re: Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 21:03
von UnSpeed
Danke, ich weiß, was Rekursion ist :)

Ich programmiere schon seit einigen Jahre und kenne grundspezifisch auch viele Strukturen (wie eben beispielsweise Rekursion :D).

Ich brauchte nur die Information, dass Variablen, die ausserhalb definiert worden sind, nicht ohne weiteres in eine Funktion übernommen werden können.
Da liegt übrigens einer der Unterschiede zu Java ;)

Damit hat sich dieses Thema erledigt --> Danke :D

Re: Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 21:43
von mutetella
UnSpeed hat geschrieben:Da liegt übrigens einer der Unterschiede zu Java
Meines Halbwissens nach gilt das bei Java aber nur für statische Variablen, die es in dieser Form bei Python nicht gibt. Alle anderen Variablen sind ebenfalls sehr wohl an den Namensraum ihrer Deklaration gebunden.

mutetella

Re: Python Variablenfehler

Verfasst: Samstag 28. Mai 2011, 23:18
von UnSpeed
mutetella hat geschrieben:
UnSpeed hat geschrieben:Da liegt übrigens einer der Unterschiede zu Java
Meines Halbwissens nach gilt das bei Java aber nur für statische Variablen, die es in dieser Form bei Python nicht gibt. Alle anderen Variablen sind ebenfalls sehr wohl an den Namensraum ihrer Deklaration gebunden.

mutetella
Das ist teilweise richtig ;)
In Java gibt es immer eine so genannte Klasse, diese Klasse ist sozusagen die Hülle eines Objektes.
Werden nun Variablen in dieser Klasse deklariert beispielsweise so:

Code: Alles auswählen

boolean entscheidung = false;
so sind sie auch in alles Methoden dieses Objektes verfügbar.
Nicht jedoch, will man sie aus einer Methode eines anderen Objektes aufrufen, dafür muss sie in der Tat static (statisch) sein :)

Aber hier gehts ja nicht um Java, deshalb bin ich jetzt mal still ;)

Edit:
BlackJack hat mich freundlicher Weise darauf aufmerksam gemacht, dass das, was ich Konstruktor nannte, natürlich nicht der Konstruktor, sondern die Klasse ist.
(Geistige Umnachtung :D)
Deshalb habe ich 'Konstruktor' in Klasse geändert.
Vielen Dank an dieser Stelle :)

Re: Python Variablenfehler

Verfasst: Sonntag 29. Mai 2011, 00:42
von BlackJack
@UnSpeed: Das ist jetzt das erste mal das ich *das* bei Java jemanden den Konstruktor nennen sehe. Das würde ich eher die Deklaration der Exemplarvariablen nennen. Denn die Variablen die man in einem Konstruktor deklariert sind auch bei Java nur innerhalb des Konstruktors sichtbar, wie bei jeder anderen Methode auch.

Code: Alles auswählen

class Test {
    int a = 42;
    Test() {
        int b = 23;  // Deklaration im Konstrukor -- nicht ausserhalb sichtbar.
    }
}
Auch wenn Du weisst was Rekursion ist — in Java wäre es ebenfalls keine gute Idee sie auf diese Weise zu verwenden. Denn auch Java garantiert keine Optimierung von Endrekursion und würde da *sehr* wahrscheinlich irgendwann mit einem übergelaufenen Aufrufstapel das Programm abbrechen.

Re: Python Variablenfehler

Verfasst: Sonntag 29. Mai 2011, 05:53
von Hyperion
mutetella hat geschrieben:

Code: Alles auswählen

#entweder
eingabe = str(raw_input('Diese Eingabe wird klein: ')).lower()
#oder
eingabe = str(raw_input('Diese Eingabe wird GROSS: ')).upper()
@mutetella: `raw_input` liefert Dir immer einen String zurück - der Aufruf von `str` ist also überflüssig.

Re: Python Variablenfehler

Verfasst: Sonntag 29. Mai 2011, 09:03
von mutetella
@Hyperion:
Ich hatte gehofft, dass das niemand mehr bemerkt... :wink:

Re: Python Variablenfehler

Verfasst: Sonntag 29. Mai 2011, 09:32
von UnSpeed
@ Blackjack:

Sicher, du hast recht --> geändert ;)

Re: Python Variablenfehler

Verfasst: Sonntag 29. Mai 2011, 21:51
von mutetella
Zur Übung für mich und auch, weil ich mein Kalenderprogramm heute nicht mehr sehen konnte :( habe ich ein wenig herumgespielt, die Eingabeschleife etwas entzerrt und das, was da IMHO nicht unbedingt hineingehört, ausgelagert:

Code: Alles auswählen

import random

LEVEL = {'L': 1, 'M': 5, 'S': 10}

def menu(level=5):
    while True:
        choice = make_choice(
            'Hauptmenu',
            '(N)eues Spiel - (L)evelauswahl - (A)nleitung - (E)nde',
            'NLAE', False)
        if choice == 'N':
            #Hier beginnt ein neues Spiel
            gamestart(level)
        elif choice == 'L':
            #Hier kommt die Levelauswahl
            choice = make_choice(
                'Levelauswahl',
                '(L)eicht - (M)ittel - (S)chwer',
                'LMS')
            if choice != 'X':
                level = LEVEL[choice]
        elif choice == 'A':
            #Hier kommt die Anleitung
            manual()
        elif choice == 'E':
            #Hier wird das Spiel beendet
            break

def make_choice(label, text, valid, cancel=True):
    if cancel:
        prompt = '|Ihre Auswahl oder \'X\' zum Abbrechen > '
        valid = valid + 'X'
    else:
        prompt = '|Ihre Auswahl > '
    choice = ''
    while True:
        print '|{0}'.format(label)
        print '|{0}'.format('-'*len(text))
        print '|{0}'.format(text)
        choice = raw_input(prompt).upper()
        print
        if choice in valid:
            return choice
        print '>>>>  FEHLERHAFTE   EINGABE  <<<<'
        print 'Bitte treffen Sie Ihre Auswahl aus'
        print '{0:^34}'.format(valid)

def gamestart(level):
    number = random.randint(0, level*10)
    print 'Level {0}: {1}'.format(level, number)

def manual():
    print 'So oder so...'

if __name__ == '__main__':
    menu()
mutetella

Re: Python Variablenfehler

Verfasst: Montag 30. Mai 2011, 13:09
von EyDu
UnSpeed hat geschrieben:In Java gibt es immer eine so genannte Klasse, diese Klasse ist sozusagen die Hülle eines Objektes.
Werden nun Variablen in dieser Klasse deklariert beispielsweise so:

Code: Alles auswählen

boolean entscheidung = false;
so sind sie auch in alles Methoden dieses Objektes verfügbar.
Nicht jedoch, will man sie aus einer Methode eines anderen Objektes aufrufen, dafür muss sie in der Tat static (statisch) sein :)
Du meinst sicher public und nicht static ;-)