Seite 1 von 2

Verfasst: Dienstag 31. Oktober 2006, 15:13
von Bamba
Entschuldigt:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Dokumente und Einstellungen\Sebastian\Desktop\Programmieren\sadf.py", line 99, in ?
    menue()
  File "C:\Dokumente und Einstellungen\Sebastian\Desktop\Programmieren\sadf.py", line 87, in menue
    main()
  File "C:\Dokumente und Einstellungen\Sebastian\Desktop\Programmieren\sadf.py", line 58, in main
    while team_a and team_b:
UnboundLocalError: local variable 'team_a' referenced before assignment

Verfasst: Dienstag 31. Oktober 2006, 15:34
von keppla
das Problem scheint in der Art des Aufrufes des Programmes zu bestehen.

In deinem Traceback ist eine Funktion menue(), die in deinen Listings nicht auftaucht. Wenn du das Programm nicht mit "python sadf.py" startest (oder deine IDE was vergleichbares tut), sondern du z.B. eine andere Datei aufrufst, die

Code: Alles auswählen

from sadf import main
main()
macht, ist __name__ != '__main__', was bedeutet, dass deine globalen Variablen team_a/b nicht gesetzt werden.

Generell bin ich der Meinung, du solltest nicht eine Funktion main haben, die globale Variablen als Teams nutzt, sondern eine Funktion mainfight(team_a, team_b), also eine Funktion, die die Teams als Argumente übergeben bekommt. Globale Variablen sind imho meist ein Zeichen für schlechtes Design.

Verfasst: Dienstag 31. Oktober 2006, 17:07
von Bamba
Darin besteht das Problem glaube ich nicht. Die Funktion ist in der gleichen Datei, ich hatte sie nur noicht hier gepostet. Wenn ich eine Funkliton habe, der die Werte TEam_a und Team_b übergeben werden, müsste es doch:

Code: Alles auswählen

def fight(team_a, team_b):
heißen, oder?

Und wenn ich dann mit

Code: Alles auswählen

f __name__ == '__main__':
    team_a = [Fighter(life, damage)
              for (life, damage) in ((2,1), (3, 1), (3, 1))]
    team_b = [Fighter(life, damage)
              for (life, damage) in ((3,1), (4, 1), (4, 1))]
team_a und team_b festlege, bekomme ich folgenden fehler:

Code: Alles auswählen

line 87, in menue
    fight()
TypeError: fight() takes exactly 2 arguments (0 given)
Sorry, dass ich das nicht verstehe, aber ich bin noch Anfänger.

Bamba

Verfasst: Dienstag 31. Oktober 2006, 18:20
von Y0Gi
Der TypeError resultiert daraus, dass du beim Aufruf der Funktion nicht so viele Parameter übergibst, wie sie erwartet (offenbar zwei). Der Aufruf lautet deinefunktion(einwert, einandererwert), also in deinem Fall wohl fight(team_a, team_b).

Verfasst: Dienstag 31. Oktober 2006, 20:52
von BlackJack
Bamba hat geschrieben:Also hier noch mal der Code:
Da fehlt wie schon jemand bemerkt hat die `menue()`-Funktion. Ich sehe auch gar nicht wie das als Programm überhaupt irgendetwas macht weil der Teil in der ``if __name__ ...`` Abfrage nur die beiden Listen mit Kämpfern erstellt.

Code: Alles auswählen

def nSoldatLevel1():
        k=Fighter(3,1)
        Liste1.append(k)
        print Liste1
        menue()
Hier fehlt vollkommen die Information wo `Liste1` herkommt. Damit das hier funktioniert muss die irgendwo auf Modulebene mal definiert worden sein. Das ist aber furchtbar unübersichtlich, darum macht man so etwas nicht. Auf Modulebene sollten soweit wie möglich nur Konstanten definiert werden. Alles andere sollte in spezifischeren Namensräumen stecken und Werte sollten Funktionen über Argumente betreten und als Rückgabewerte verlassen. Dann lässt sich ein Programm viel einfacher nachvollziehen und verstehen.

Wenn man mal den Aufruf von `menue()` weglässt, dann kann man den Aufruf dieser Funktion auch einfach durch ein ``Liste1.append(Fighter(3, 1))`` ersetzen. Das ist ein bischen zu einfach um extra einen Namen dafür zu vergeben. IMHO.

Code: Alles auswählen

def verteilen():
    print len(Liste1),"Kaempfer stehen zur Verfuegung"
    Wahl=input("Wahl: ")
    team_b.extend(Liste1[0:Wahl])
Hier auch wieder: `Liste1` und `team_b` sollten als Argumente in die Funktion kommen. Dann lässt sich diese Funktion auch für beide Teams verwenden.

Wie man die dann aus `Liste1` löscht solltest Du aber eigentlich schon selbst können.

Code: Alles auswählen

def filter_dead_fighters(fighters):
    return [fighter for fighter in fighters if not fighter.is_dead()]

def fight(team_a, team_b):
    for fighter_a, fighter_b in zip(team_a, team_b):
        fighter_a.life -= fighter_b.damage
        fighter_b.life -= fighter_a.damage
    return map(filter_dead_fighters, (team_a, team_b))


def main():
    while team_a and team_b:
        print 'A:', team_a
        print 'B:', team_b
        print '-' * 20
        team_a, team_b = fight(team_a, team_b)

    if team_a:
        winner_name = 'A'
        winner_team = team_a
    else:
        winner_name = 'B'
        winner_team = team_b
    print 'Winner is %s: %r' % (winner_name, winner_team)

if __name__ == '__main__':
    global team_a
    team_a = [Fighter(life, damage)
              for (life, damage) in ((2,1), (3, 1), (3, 1))]
    global team_b
    team_b = [Fighter(life, damage)
              for (life, damage) in ((3,1), (4, 1), (4, 1))]
Das ``global``, dessen blosse Existenz Du am besten sofort komplett vergisst, hat an dieser Stelle keine Wirkung. Das macht nur innerhalb von Funktionen Sinn.

Zu der Namensgebung: Ich ging beim ersten Versuch ja davon aus, das in `fight()` der komplette Kampf bis zum bitteren Ende abgewickelt wird. Von den jetzt implementierten Kampfregeln wäre der Name `fight()` für die `main()` passender und die alte `fight()` würde eher `round()` heissen.

Verfasst: Mittwoch 1. November 2006, 14:55
von Bamba
Hallo Leute,

vielen Dank für eure Antworten. die Funktion menue() hatte ich hier noch nicht aufgelistet, weil sie unerheblich ist. Ich wollte mir damit im Laufzeitmodus nur aufrufarbeit ersparen. Liste1 wird am Anfang des Skriptes mit Liste1=[] inizialisiert. Das hatte ich übersehen zu posten. Jetzt komen bei mir aber nur noch Fehler:

Code: Alles auswählen

def verteilen(Liste1,team_a):
    print len(Liste1),"Kaempfer stehen zur Verfuegung"
    Wahl=input("Wahl: ")
    team_a.extend(Liste1[Wahl])
            
def filter_dead_fighters(fighters):
    return [fighter for fighter in fighters if not fighter.is_dead()]

def runde(team_a, team_b):
    for fighter_a, fighter_b in zip(team_a, team_b):
        fighter_a.life -= fighter_b.damage
        fighter_b.life -= fighter_a.damage
    return map(filter_dead_fighters, (team_a, team_b))

def fight():
    team_a = [Fighter(life, damage)
              for (life, damage) in ((2,1), (3, 1), (3, 1))]
    team_b = [Fighter(life, damage)
              for (life, damage) in ((3,1), (4, 1), (4, 1))]
    while team_a and team_b:
        print 'A:', team_a
        print 'B:', team_b
        print '-' * 20
        team_a, team_b = fight(team_a, team_b)

    if team_a:
        winner_name = 'A'
        winner_team = team_a
    else:
        winner_name = 'B'
        winner_team = team_b
    print 'Winner is %s: %r' % (winner_name, winner_team)
Wäre wirklich toll, wenn ihr mir noch mal helfen könntet.

Bamba

Verfasst: Mittwoch 1. November 2006, 15:41
von BlackJack
Vielleicht ist das ganze noch ein bischen zu gross für Dich und Du solltest nochmal ein paar einfachere Sachen programmieren um Dich mit dem Umgang mit Funktionen vertraut zu machen und zu lernen welche Namen wo sichtbar bzw. nicht sichtbar sind.

Lauter Fehler glaube ich nicht, weil ja immer nur eine Ausnahme zum Abbruch führt. Einen Fehler kann ich auf Anhieb entdecken, der eigentlich eine sehr verständliche Fehlermeldung zur Folge hat. Du musst lernen wie man solche "Tracebacks" liest. Für gewöhnlich zeigen die recht genau was wo schiefgelaufen ist.

(Das Problem, welches ich gerade meine steckt in Zeile 24 im Quelltext von Deinem letzten Beitrag.)

Ansonsten musst Du einfach mal Python-Interpretierer spielen und den Quelltext Zeile für Zeile durchgehen und nachvollziehen was da im Einzelnen passiert.

Verfasst: Mittwoch 1. November 2006, 18:21
von Bamba
Danke. Statt das da fight() steht, habe ich jetzt dort runde() hingeschrieben. Und nein, ich werde das jetzt durchziehen. NOch eine Frage: Damit team_a und team_b nicht immer die gleichen Werte haben, sondern veränderbar sind, muss ich sie aus fight() rausnehmen:

Code: Alles auswählen

team_a = [Fighter(life, damage)
              for (life, damage) in ((2,1), (3, 1), (3, 1))]
team_b = [Fighter(life, damage)
              for (life, damage) in ((3,1), (4, 1), (4, 1))]
Jetzt stehen sie so im Code. Aber warum funktioniert das dann nicht mehr?

Bamba

Verfasst: Mittwoch 1. November 2006, 20:22
von BlackJack
Keine Ahnung. Was heisst funktioniert nicht? Gibt's eine Fehlermeldung? Explodiert der Rechner?

Wie kommen die Listen mit den Kämpfern denn jetzt in die `fight()` Funktion?

Verfasst: Donnerstag 2. November 2006, 12:45
von keppla
Bitte nicht als Beledigung auffassen: Lerne bitte, wie man Fragen stellt, die beantwortbar sind, bevor du fragst.
Jetzt komen bei mir aber nur noch Fehler
Aber warum funktioniert das dann nicht mehr?
Das sind schlechte Fragen, weil sie so vage gestellt sind, dass die Antwort einfach ist: "weil du was falsch machst".

Eine gute Frage stellt das erwartete Verhalten dem tatsächlichen Verhalten gegenüber. Also nicht "Das essen ist Falsch" sondern "Ich habe ein Whoppermenu mit Käse bestellt, aber eines ohne Käse bekommen".

Wenn das tatsächliche Verhalten ein Laufzeitfehler ist, DANN POSTE IHN BITTE EINFACH, lass dich nicht dreimal drum bitten.

Verfasst: Donnerstag 2. November 2006, 13:55
von Leonidas
keppla hat geschrieben:Das sind schlechte Fragen, weil sie so vage gestellt sind, dass die Antwort einfach ist: "weil du was falsch machst".
Da gehört auch der Link zu "Wie man Fragen richtig stellt" dazu.

Verfasst: Donnerstag 2. November 2006, 14:33
von Bamba
Hallo,

OK. Sorry, ich glaube ich muss noch einiges lernen. Aber das lässt sich jetzt nicht ändern.

Mein Fehler war, dass sie Listen nicht mehr in die fight Funktion übergeben wurden. Es reichte nicht fight(team_a,team_b) hinzuschreiben. Und hier die Fehlermeldung:

Code: Alles auswählen

TypeError: fight() takes exactly 2 arguments (0 given)
Sorry nochmal.