TypeError: bad operand type for unary +: 'str'

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
Dexter1997
User
Beiträge: 92
Registriert: Sonntag 2. Dezember 2012, 21:13

Hallo Freunde, ich erhalte seit neuestem immer diese kryptische Fehlermeldung:

Traceback (most recent call last):
File "C:\Dokumente und Einstellungen\Gastkonto\Desktop\Python\Programme\Eigenes\Rollenspiel.py", line 100, in <module>
"Schattenklinge: Schaden + "]), str(Neu_Waffe_Schaden)
TypeError: bad operand type for unary +: 'str'

Das Problem muss irgendwo hier liegen:

Code: Alles auswählen

            if get_Ausruestung == 1: # Neue Waffe
                Wert = random.randint(1 * Level, 2 * Level)
                Neu_Waffe_Schaden = Wert
                Neu_Waffe_Name = random.choice(["Klinge der Angst: Schaden + ", "Todesschwert: Schaden + ", +\
                                                "Schattenklinge: Schaden + "]) + str(Neu_Waffe_Schaden)
                print "Du hast ein Schwert gefunden: "
Könnt ihr mir da weiterhelfen?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Richtig und zwar in der Zeile vor der, die die Fehlermeldung zeigt.
Ein unaeres + ist eines, das nur ein Argument hat, wie zum Beispiel ``+ 1``. Schau mal wo so etwas bei dir auftaucht.
BlackJack

@Dexter1997: Na das ist doch recht offensichtlich:

Code: Alles auswählen

In [1]: + 'hello'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/home/bj/<ipython-input-1-7a934349034f> in <module>()
----> 1 + 'hello'

TypeError: bad operand type for unary +: 'str'
Ein einzelnes ``+`` vor einer Zeichenkette macht ja auch keinen Sinn.

Unschön ist auch das in alles Auswahlmöglichkeiten am Ende der selbe Text stehen muss, man den also pro Auswahlmöglichkeit tippen muss(te), statt nur *einmal*.

Ein \ am Zeilenende ist hier übrigens nicht nötig da es noch offene Klammern gibt und der Compiler deshalb schon weiss, dass die logische Zeile noch nicht zuende sein kann.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ergänzend zu meinen Vorpostern ist da noch viel mehr unschönes drin! Ich gehe das mal durch...

Code: Alles auswählen

if get_Ausruestung == 1: # Neue Waffe
``get_Ausruestung`` klingt eher nach Funktionsaufruf als nach Attribut - das solltest Du ändern! Gute Namensgebung gehört genauso zum Fundament Deiner Anwendung wie eine gute Strukturierung; das eine ist ohne das andere kaum etwas wert.

Generell kann man sich in dieser Stelle die Frage stellen, ob es noch zig andere ``elif...``-Zweige gibt, in denen zig andere Stellen Code stehen, die die umschließende Funktion auf Dauer unleserlich (weil viel zu lang und komplex!) und zudem schlecht wartbar machen (``wert == 3`` soll jetzt auf 5 prüfen, 2 und 6 sollen dasselbe machen, dann soll soll ein anderer dazu kommen, usw).

Sinnvoller wäre es dann, die Rümpfe der ``if...elif..else``-Kaskade in separate Funktionen zu teilen und diese nur aufzurufen. Als nächsten Schritt sollte man sich dann überlegen, ob man nicht statt der ``if...elif...else``-Kaskade ein dynamisches Dispatching einbaut, durch welches, basierend auf einer geeigneten Datenstruktur, die Verzweigung allgemeingültig beschrieben wird. Etwa in der Art:

Code: Alles auswählen

# Dispatching definieren - kann u.U. durchaus auf Modulebene sein!
actions = (
    (get_sword, "Du hast ein Schwert gefunden"),
    (get_armour, "Du hast eine Rüstung gefunden")
    # usw.
)
# irgend wie im Ablauf ermitteln, was passiert
action_index = ...

# Action aufrufen
actions[action_index][0]()
print actions[action_index][1]()
Rund um das Thema Daten zusammenfassen und Dispatching hilft Dir vielleicht folgendes Tutorial: Textmenüs

Folgendes kann man kompakter schreiben:

Code: Alles auswählen

Wert = random.randint(1 * Level, 2 * Level)
Neu_Waffe_Schaden = Wert

# besser:
Neu_Waffe_Schaden = random.randint(1 * Level, 2 * Level)
Du benutzt ``Wert`` nur an einer Stelle als temporäre Variable, dessen Wert Du *sofort* wieder an einen neuen Namen, nämlich ``Neu_Waffe_Schaden``, bindest. Das ist umständlich und macht den Code weniger lesbar.

Die nächsten beiden Zeilen hatte BlackJack ja schon kritisiert. Zum einen suggerieren Deine Namen, dass da etwas nicht gut läuft (``Neu_Waffe_*``), zum anderen solltest Du zusammengehörige Dinge in zusammengehörige Datenstukturen packen! Man kann sich für eine Waffe durchaus eine Klasse vorstellen, es ginge auch ohne, wenn Du noch nicht so weit bist beim Lernen:

Code: Alles auswählen

# Dictionary als Datenstruktur einer Waffe
weapon = {"name": "Klinge der Angst", "damage": 12}

def describe_weapon(weapon):
    return "{name}: Schaden {damage}".format(**weapon)

describe_weapon(weapon)
> 'Klinge der Angst: Schaden 12'
Ein wesentlicher Vorteil ist hierbei, dass der Name der Waffe und der Schadenswert *zusammengefasst* in *einer* Datenstruktur stehen! Mit Deiner aktuellen Lösung könnte es passieren, dass Du z.B. nur den Namenswert der Spielerwaffe änderst, den Schadenswert aber vergisst! Eine potenzielle Fehlerquelle...

In einer Funktion, die den Spieler neue Waffen finden lässt, musst Du dann nur eine solche Struktur zusammenbauen. Die Namen kannst Du dabei statisch vorgeben (oder später gar in eine externe Datei auslagern, um Inhalte ohne Programmänderung zu ermöglichen):

Code: Alles auswählen

def generate_weapon():
    weapon_names = (
        "Klinge der Angst",
        "Todesschwert",
        "Schattenklinge",
    )
    return {
        "name": random.choice(weapon_names), 
        "damage": random.randint(1 * Level, 2 * Level)
    }

# testen:

describe_weapon(generate_weapon())
> 'Schattenklinge: Schaden 3'

describe_weapon(generate_weapon())
> 'Schattenklinge: Schaden 4'

describe_weapon(generate_weapon())
> 'Todesschwert: Schaden 4'
Um kurz noch einmal auf die Namensproblematik zurückzukommen. Das Präfif "Neu_" suggeriert hier, dass es auch eine "alte" Waffe im Spiel gibt. Das ist ein wenig krude... denn irgend wann ist die neue Waffe ja nicht mehr "neu" ;-) Ich stelle mal die Vermutung an, dass Du irgend wann die Werte der aktuellen Spieler-Waffe mit denen der neuen Waffe überschreibst, richtig? (Also evtl. wird der Spieler gefragt, ob er die neue Waffe behalten will?) Was ist denn aber zu Beginn eines Spiels, wenn der Spieler noch *keine* Waffe hat? Dann gibt es ja auch keine "alte" Waffe? Ich würde das Präfix eher nicht wählen und irgend wie dem "Spieler-Objekt" ein Attribut geben, welches die *aktuell* von ihm benutze Waffe repräsentiert. ``current_weapon`` oder schlicht ``weapon`` sollte reichen. In einer Funktion wie ich sie oben gezeigt habe, wird zwar eine "neue" Waffe erstellt, aber im Grunde ist die Information irrelevant, denn wenn der Spieler sie wählt ist sie ja nicht mehr "neu" und wenn nicht, interessiert es auch nicht, dass sie "neu" war ;-) Ich würde das Ding eher "found_weapon" nennen; also in der Art:

Code: Alles auswählen

found_weapon = generate_weapon()
describe_weapon(found_weapon)
if(ask_player_to_keep_it()):
    # Spieler will die neue Waffe nutzen → seine bisherige Waffe ersetzen!
    weapon = found_weapon
So eine Menge Tobak... ich hoffe es hilft Dir ein wenig!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

2. Codeblock, Zeile 12:

Code: Alles auswählen

print actions[action_index][1]()
muss wohl

Code: Alles auswählen

print actions[action_index][1]
lauten.
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Japp :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten