Problem beim Aufruf von Methoden

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.
Antworten
Benutzeravatar
kevind
User
Beiträge: 71
Registriert: Montag 22. Oktober 2012, 20:23
Wohnort: /dev/null

Hallo Zusammen!

In meinem Textgame soll der spieler verschiedene attacken auswählen können, diese sind mit einer ID und Name in einer Klasse/Instanz des Spielers gespeichert. Es existieren gleichnamige Funktionen zu den attacken welche ich durch eingabe des Users ausführen möchte.

Klasse des Spielers:

Code: Alles auswählen

class character():

    def __init__(self, name, npc):
        #character properties
        self.npc = npc
        self.name = name
        self.level = 1
        #character status values
        self.strengh = 10
        self.vitality = 100
        self.defense = 5
        self.dextery = 15
        self.combat_experience = 100
        #abilitys
        self.attacks = {1: "Kick", 2: "Punch"}
        #base damage
        self.base_damage = int(self.strengh + (self.dextery / 3) +
        (self.combat_experience / 10))
attacken:

Code: Alles auswählen

class Skills():

    def __init__(self, character_instance):
        self.chara = character_instance

    def Punch(self):
        self.punch_dmg = int(self.chara.base_damage + 10)
        return self.punch_dmg

    def Kick(self):
        self.kick_dmg = int(self.chara.base_damage + 5)
        return self.kick_dmg
Abschnitt der Skill auswahl:

Code: Alles auswählen

def attack(player):
# argument "player" is the character instance
    atk_input = None
    if player.npc is True:  # check if "player" is a npc
        atk_input = random.randint(1, 2)
    elif player.npc is False:  # check if "player" is a player
        print("-----------")
        for attack_id, attack_name in player.attacks.items():
            print(attack_id, attack_name)
        atk_input = int(input(prompt))
        attack = player.attacks[atk_input]  # name of the attack
Die ausgabe sieht ca so aus:

Code: Alles auswählen

1 Kick
2 Punch
Angenommen der Spieler gibt 1 ein (somit steht in der Variable attacke nun "Kick"), dann möchte ich dass die methode player.Kick aufgerufen wird.
Ich möchte es einfach variabel halten und ewige if, elif,elif,elif vermeiden.
Hab bereits mit eval() versucht das player.attack irgendwie umzuwandeln aber ohne Erfolg.

Wäre um anregungen und Tipps dankbar.

Gruss, Kev
cmax
User
Beiträge: 14
Registriert: Dienstag 22. Januar 2013, 21:36

z.B. so:

Code: Alles auswählen

class character():

    def __init__(self, name, npc):
        ...
        self.attacks = {1: attack('kick',5), 2: attack('punch',5)}
        ...

    def attacks(self,opponent,attackNr):
        a = self.attacks[i]
        print a.name
        opponent.vitality -= int(self.chara.base_damage + a.damage)


class attack():

    def __init__(self,name,damage):
        self.name
        self.damage
        ...
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Warum stecken deine Attacken denn in einer Klasse? Du hast keinen echten geteilten Zustand auf dem die Methoden operieren.

Loest man es auf einfache Funktionen auf, kann man direkt die Funktionen benutzen:

Code: Alles auswählen

class Character():
    ....
    self.attacks = [('Kick', lambda: self.base_damage + 5),
                        ('Punch', lambda: self.base_damage + 10)]
    ....
    for i, attack in enumerate(self.attacks, 1):
        name, _ = attack
        print("%d: %s" % i, name)
    choice = int(input(prompt))
    name, dmg_function = self.attacks[choice - 1]
    ....
Anstelle der Lambda Funktionen kann man natuerlich auch benannte nehmen .. oder gebundene Methodenobjekte, falls tatsaechlich so eine Skill Klasse noetig werden sollte.

Daneben sei dir PEP 8 empfohlen.
Benutzeravatar
kevind
User
Beiträge: 71
Registriert: Montag 22. Oktober 2012, 20:23
Wohnort: /dev/null

Erstmals vielen dank das hat mich wirklich weitergebracht !
cmax hat geschrieben:z.B. so:

Code: Alles auswählen

class character():

    def __init__(self, name, npc):
        ...
        self.attacks = {1: attack('kick',5), 2: attack('punch',5)}
        ...

    def attacks(self,opponent,attackNr):
        a = self.attacks[i]
        print a.name
        opponent.vitality -= int(self.chara.base_damage + a.damage)


class attack():

    def __init__(self,name,damage):
        self.name
        self.damage
        ...
Sollte vermutlich so aussehen:

Code: Alles auswählen

def attacks(self,opponent,attackNr):
    a = self.attacks[[b]attackNr[/b]]

und problematisch ist noch das die methode attacks und das attribut attacks den selben Namen haben.

Denn wenn ich folgendes versuche:

Code: Alles auswählen

dude = character("dude", False)
dude.attacks(enemy, 1)
sagt er das dict object nicht callable ist. Denke er greift hier direkt auf das Attribut zu und nicht auf die Methode.

Wenn ich irgendwo falsch liege bitte sagt es mir.

@cofi
Ich habe deswegen die Attacken in eine Klasse eingebaut weil ich noch die Idee hatte den Attacken eine art "cooldown" und andere attribute zu verpassen, welche sozusagen abhängig davon sind welcher Character welche attacke wie oft ausführt. Wenn Character X attacke Punch 100 mal ausführt dann wird diese bei Character Y immer ineffektiver. Daher wollte ich die Attacken pro Character instanzieren.

Andererseits wusste ich nicht was besser ist, kann vermutlich auch nicht so weit vorausdenken da meine Python skills noch nicht so ausgeprägt sind und wenig Erfahrung vorhanden ist ;)

Den Style guide habe ich mir schon angeschaut und versuche ihn vermehrt zu verwenden.

Lambda kenne ich noch nicht, werde mir das aber auch noch ansehen.

Gruss, Kev
cmax
User
Beiträge: 14
Registriert: Dienstag 22. Januar 2013, 21:36

kevind hat geschrieben:Sollte vermutlich so aussehen:
...
und problematisch ist noch das die methode attacks und das attribut attacks den selben Namen haben.
Du hast beide Fehler im Suchquellcode gefunden. :mrgreen:

Nein, sorry. Hatte es nur schnell ohne Test runtergetippt mit Fokus auf die Objekte im dict. :oops:
Benutzeravatar
kevind
User
Beiträge: 71
Registriert: Montag 22. Oktober 2012, 20:23
Wohnort: /dev/null

Hallo nochmals,

so ich habe nun etwas herumgespielt und möchte euch mein Resultat zeigen, mit bitte um feedback.

Meine Anforderungen waren:

Irgendwo werden alle Skills definiert (Hier in Dictionarys)
Jeder Charakter erhält eine liste mit erlernten/verfügbaren skills (Hier die Liste "autos" (könnte dann auch in der Klasse des Charakters stehen))
Skills können einfach aufgelistet werden und per Nummern eingabe verwendet werden.
Skills haben attribute wie zb. "Cooldown" die einzigartig pro Skills und Charakter sind. (Sobald die skills instanziert sind kann damit "schön" gearbeitet werden)

Stellt euch einfach vor das es keine Autos sondern Skills sind ;)

ps: Gibts es eine andere Möglichkeit als "x = []" um "x" zu initalisieren ?

Code: Alles auswählen

class car(object):

    def __init__(self, name, ps, sitze):
        self.name = name
        self.ps = ps
        self.sitze = sitze

    def ausgabe(self):
        print(self.name, self.ps)


dict_opel = {"name:": "Opel", "PS:": 300, "sitze:": 4}
dict_mazda = {"name:": "Familywagen:", "PS:": 100, "sitze:": 5}
dict_porsche = {"name:": "Sportwagen:", "PS:": 500, "sitze:": 2}
dict_audi = {"name:": "Audi A8", "PS:": 500, "sitze:": 4}

autos = [dict_opel, dict_mazda, dict_porsche, dict_audi]

x = []

print("Wähle ein Auto")
for index, obj in enumerate(autos):
    print(index, autos[index]["name:"])
    x.append(car(obj["name:"], obj["PS:"], obj["sitze:"]))


auto = int(input(">>"))
print("Du steigst in den {0} ein und fährst davon", x[auto].name)

print("--"*10)
for index, car in enumerate(x):
    print(index, car.name)
Danke euch !
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Code: Alles auswählen

class Car():
    def __init__(self, name, ps, size):
        self.name = name
        self.ps = ps
        self.size = size

    def __str__(self):
        return '%s %s' % (self.name, self.ps)
    

cars = [Car(*attr) for attr in [('Opel', 300, 4),
                               ...
                           ]]

print('Wähle ein Auto:')
for i, car in enumerate(cars):
    print(i, car.name)
...
Warum noch das Dictionary, wenn du schon eine Klasse dafuer hast? `cars` ist nun übrigens dein `x` (Was davor auch schon redundant zu `autos` war)

PEP 8 sei dir immernoch empfohlen, was hier ganz nuetzlich ist das passende Programm: http://pypi.python.org/pypi/pep8/1.4.2
Benutzeravatar
kevind
User
Beiträge: 71
Registriert: Montag 22. Oktober 2012, 20:23
Wohnort: /dev/null

Ja den Style guide habe ich im Hinterkopf, habe aber leider wenig Zeit und meistens is die Lust zu coden grösser als den Guide zu lesen ... ich werde es aber bald machen, versprochen ;)

Danke für den Link!

Hier wird meine Anforderung


- Irgendwo werden alle Skills definiert (Hier in Dictionarys)
- Jeder Charakter erhält eine liste mit erlernten/verfügbaren skills (Hier die Liste "autos" (könnte dann auch in der Klasse des Charakters stehen))


Aber nicht gedeckt, denn alle skills stecken in ´cars´. Oder übersehe ich etwas ?

Das Dictionary stellt alle verfügbaren Skills dar, in der Liste ´autos´ werden alle Skills zum jeweiligen Charakter gespeichert. (sollte wohl besser als Attribut in die charakter Klasse).

und mit der Klasse erstelle ich aus den beiden Informationen dann die Instanzen der einzelnen Fähigkeiten. So hätte ich jetzt den Sinn und Zweck des ganzen beschrieben.


**na super jetzt vermische ich Autos und Skills... kein Wunder wenn ich keine Antworten mehr bekomm :P
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

kevind hat geschrieben:Aber nicht gedeckt, denn alle skills stecken in ´cars´. Oder übersehe ich etwas ?
Ja, das (zugegeben abgekuerzte) Listen-Literal in der LC, die cars erstellt.
Benutzeravatar
kevind
User
Beiträge: 71
Registriert: Montag 22. Oktober 2012, 20:23
Wohnort: /dev/null

Ja ich sehe die Liste, einen punkt habe ich noch:

hier habe ich noch die zuordnung der Skills für jeden Charakter, diese fehlt bei dir oder ?

Code: Alles auswählen

...
autos_dude = [dict_opel, dict_mazda, dict_porsche, dict_audi]
autos_enemy = [dict_porsche, dict_audi]
...
Und deine ´cars´ zuweisung macht das selbe wie meine for schleife "for index, obj..." nur kompakter oder ?


(was ist mit LC gemeint?)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

kevind hat geschrieben:hier habe ich noch die zuordnung der Skills für jeden Charakter, diese fehlt bei dir oder ?
Das liegt daran, dass die Fahrzeuge nicht so viel mit einem Charakter zu tun haben ;-) Dabei fällt mir auf: meinst du vielleicht Player und nicht Character? Und statt "enemy" meinst du wohl eher "opponent".
kevind hat geschrieben:

Code: Alles auswählen

...
autos_dude = [dict_opel, dict_mazda, dict_porsche, dict_audi]
autos_enemy = [dict_porsche, dict_audi]
...
Hier siehst du auch gleich, warum das benennen nach Datenstrukturen (dict_*) ein schlecte Idee: Datenstrukturen ändern sich gerne mal, besonders bei dynamischen Sprachen wie Python und dann müsstest du alle Namen anpassen oder hast falsche Namen.
kevind hat geschrieben:Und deine ´cars´ zuweisung macht das selbe wie meine for schleife "for index, obj..." nur kompakter oder ?
Ja, bis auf Ausgabe.

kevind hat geschrieben:(was ist mit LC gemeint?)
List Comprehension
Das Leben ist wie ein Tennisball.
Benutzeravatar
kevind
User
Beiträge: 71
Registriert: Montag 22. Oktober 2012, 20:23
Wohnort: /dev/null

Danke EyDu,
kevind hat geschrieben:

Code: Alles auswählen

...
autos_dude = [dict_opel, dict_mazda, dict_porsche, dict_audi]
autos_enemy = [dict_porsche, dict_audi]
...
Hier siehst du auch gleich, warum das benennen nach Datenstrukturen (dict_*) ein schlecte Idee: Datenstrukturen ändern sich gerne mal, besonders bei dynamischen Sprachen wie Python und dann müsstest du alle Namen anpassen oder hast falsche Namen.
Was gibt es hier denn für möglichkeiten ? Irgendwas muss ich ja angeben woher die Daten kommen sollen, ob ich es jetzt direkt als Liste einfüge wie cofi das geschrieben hat:

Code: Alles auswählen

cars = [Car(*attr) for attr in [('Opel', 300, 4),
                               ...
                           ]]
Oder ich es über Dicts mache macht doch kaum ein unterschied.

Irgendwie dreh ich mich im Kreis :K
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

EyDu meint damit, dass `dict_opel` ein schlechter Name ist, weil er aussagen soll, dass sich dahinter ein Dictionary verbirgt. Das ist in dem Moment zwar kein Problem, wenn du die Daten weiterhin als Konstante behandelst, bringt aber auch keinen Mehrwert. Zum Problem wird es aber ganz schnell als Name eines Argumentes in einer Funktion, wo sich der Name ganz schnell als "Luege" herausstellen kann.

Und dann haben wir noch ein Kommunikationsproblem: Du redest eine andere Sprache als diejenigen, die deine Posts lesen. EyDu hat es schon angeschnitten: Was haben jetzt die Autos mit dem anderen Kram zu tun? Sind die Autos deine "Charakter" oder deine "Skills"? Und was soll das jeweils andere sein?

Wenn du eine Loesung fuer dein eigentliches Problem haben willst, dann musst du uns auch das - und genau das - Problem schildern. Nicht ueber halbgare Analogien, die du dann selbst wieder vermischst.
Benutzeravatar
kevind
User
Beiträge: 71
Registriert: Montag 22. Oktober 2012, 20:23
Wohnort: /dev/null

Nochmals danke,

ja das ich hier mit den Autos angefangen hab war beschissen. Hätte das erst Thread bezogen umbauen sollen.

Generell sollte ich mir angewöhnen gleich ordentliche Namen zu verwenden und mich in Style Guide einlesen... würde glaube ich einige Missverständnisse unterbinden ;)

Greetz Kev.
Antworten