Warum wird else nicht ausgeführt?

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.
Miliano
User
Beiträge: 8
Registriert: Samstag 14. November 2020, 20:40

Samstag 14. November 2020, 21:03

Hallo erstmal,

ich bin neu hier und auch noch relativ neu in Python, also bitte habt Nachsicht! ;)

Ein Punkt off topic vorweg: Bei den Bekanntmachung "Vor dem Posten lesen" funktioniert der Link zu den Regeln nicht. Ich weiß, klickt außer mir eh keiner drauf, aber so kann man sich nicht dran halten. Da ich forentechnisch nicht ganz unerfahren bin, hoffe ich trotzdem nicht zu böse anzuecken. Ansonsten gern Bescheid geben ...

Jetzt zur eigentlichen Frage:
Dazu ein Auszug aus meinem Code: (aaa, bbb, ccc, ... wurden nur unkenntlich gemacht und haben eigentlich aussagekräftige Namen - ist hierbei aber nicht relevant)

data = json.loads(message)
if ("aaa" == data["intent"]["name"]):
print ("bbb")
elif ("ccc" == data["intent"]["name"]):
if ("ddd" == data["slots"]["eee"]):
print ("fff") # Bis hier funktioniert alles Fehlerfrei
else: # funktioniert nicht
print ("ggg")

Wenn ich den Part if ("ddd" == data["slots"]["eee"]): mit irgendwas simplem ersetzte, wie if 4 > 5, wird else ausgeführt, aber warum denn nicht wenn if ("ddd" == data["slots"]["eee"]): nicht true ist?
Irgendwas übersehe ich da, aber ich komme nicht drauf was!? Ich hoffe ist noch halbwegs verständlich was ich meine, sonst gerne nachfragen! :)
Hoffe ihr gebt mir einen Tipp

Gruß und schönes Wochenende!
Mili
Benutzeravatar
__blackjack__
User
Beiträge: 8716
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Samstag 14. November 2020, 21:44

@Miliano: Ohne die Daten kann man das nicht nachvollziehen. Zeig doch mal ein eigenständig lauffähiges Beispiel bei dem das Verhalten auftritt.

Anmerkungen zum Quelltext: Um die Bedingungen gehören keine unnötigen Klammern und zwischen Funktionsname und öffnende Klammern gehört kein Leerzeichen. Hast Du bei `loads()` ja auch nicht gemacht. Warum dann bei `print()`?
long long ago; /* in a galaxy far far away */
Benutzeravatar
__blackjack__
User
Beiträge: 8716
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Samstag 14. November 2020, 21:51

Oder mal anders herum: Bei mir wird hier der ``else``-Zweig ausgeführt:

Code: Alles auswählen

data = {"intent": {"name": "ccc"}, "slots": {"eee": "nicht ddd"}}
if "aaa" == data["intent"]["name"]:
    print("bbb")
elif "ccc" == data["intent"]["name"]:
    if "ddd" == data["slots"]["eee"]:
        print("fff")
    else:
        print("ggg")
Was ist bei Dir anders?

Was auch ein bisschen komisch ist, ist die Reihenfolge bei den Vergleich. Das ist IMHO etwas unnatürlich. Man macht das in bestimmten anderen Programmiersprachen so um Fehler zu vermeiden falls man sich vertippt und nur *ein* ``=`` da stehen hat. Da wäre dann eine Zuweisung an eine Zeichenkette ein Fehler, eine Zuweisung an einen Platz in einer Datenstruktur aber nicht. Dieses Problem gibt es in Python nicht, weil da an dieser Stelle keine Zuweisung stehen kann, beziehungsweise die nicht mit einem ``=`` gemacht würde. Ein einzelnes ``=`` ist da in beiden Fällen ein Syntaxfehler.
long long ago; /* in a galaxy far far away */
Miliano
User
Beiträge: 8
Registriert: Samstag 14. November 2020, 20:40

Samstag 14. November 2020, 23:39

Hallo, schon mal Danke für die Hinweise mit den überflüssigen Klammern und Leerzeichen!

Okay, dann einmal mein kompletter Code, denn ich finde keinen Unterschied zu deinem Beispiel, aber es funktioniert nicht ...
Wird dann aber etwas länger ;)

Code: Alles auswählen

import websocket
import requests
import json
import time
from matrix_lite import led

# Funktion "say"
def say(text):                                              # Funktion "say" mit Option "text"
    url = "http://localhost:12101/api/text-to-speech"       # Variable url für Text to Speech
    requests.post(url, text.encode("utf-8"))                # Modul Request mit Methode post, übergibt Variable "url" + "text"

# Intents (Ereignisse aus Rasspy) werden abgearbeitet
def on_message(ws, message):                                # Funktion on_message
    data = json.loads(message)                              # Variable data mit json.loads "message" füllen
    print("**Neues Event ausgelöst**")                      # "Neues Event ausgelöst" ausgeben
    print(data)                                             # Die Daten aus der mit der Json Message gefüllten Variablen ausgeben

    if "Led" == data["intent"]["name"]:                     # Wenn "LED" gleich ist mit Kategorie "intent" und Inhalt von "name" aus der Variablen "data"
        led.set(data["slots"]["color"])                     # Matrix Lite: Led setzen auf Kategorie "slots" und Inhalt von "color"
        say("Setze Licht auf: " + data["slots"]["color"])   # Ruft die Funktion "say" auf und übergibt als Text "Setze Licht auf" + Kategorie "slots" und Inhalt von "color"
    elif "Hallo" == data["intent"]["name"]:
        say("Hallo")
    elif "Datum" == data["intent"]["name"]:
        date = (time.strftime("%d.%m.%Y"))
        say(date)
    elif "Uhr" == data["intent"]["name"]:
        uhr = (time.strftime("%H:%M"))
        say(uhr)
    elif "Kodi" == data["intent"]["name"]:
        url = 'http://192.168.xxx.xxx:8080/jsonrpc'
        pas = ('xxx', 'xxx')
        #if "Pause" == data["slots"]["pause"] or "Play" == data["slots"]["pause"]:
        #    befehl = {"jsonrpc":"2.0","method":"Player.PlayPause","params":{"playerid":1},"id":1}
        #    x = requests.post(url, auth=pas, data=json.dumps(befehl, indent=4))
        #    if x.text == '{"id":1,"jsonrpc":"2.0","result":{"speed":0}}':
        #        say ("pause")
        #    elif x.text == '{"id":1,"jsonrpc":"2.0","result":{"speed":1}}':
        #        say ("Wiedergabe")
        #    else:
        #        say ("Befehl nicht möglich")
        if "stumm" == data["slots"]["mute"]:
            print("if")
            print(data["slots"]["mute"])
        else:
            print("else")
            #befehl = {"jsonrpc":"2.0","permission":"ControlPower","method":"Application.SetMute","params":{"mute":"toggle"},"id":1}
            #x = requests.post(url, auth=pas, data=json.dumps(befehl, indent=4))
            #if x.text == '{"id":1,"jsonrpc":"2.0","result":true}':
            #    say ("stumm")
            #elif x.text == '{"id":1,"jsonrpc":"2.0","result":false}':
            #    say ("Ton an")
            #else:
            #    say ("error" + x.text)
def on_error(ws, error):                                    # Funktion on_error
    print(error)                                            # "error" ausgeben

def on_close(ws):                                           # Funktion on_close
    print("\n**Verbindung beendet**\n")                     # "Verbindung beendet" ausgeben

def on_open(ws):                                            # Funktion on_open
    print("\n**Verbindung aufgebaut**\n")                   # "Verbindung aufgebaut" ausgeben

# Start web socket client
if __name__ == "__main__":                                  # Wird nur ausgeführt, wenn diese Datein die Hauptdatei ist und nicht wenn sie als Modul geladen wird
    ws = websocket.WebSocketApp("ws://localhost:12101/api/events/intent",   # Websocket öffnen mit URL
                              on_message = on_message,      # Bei Meldung Funktion on_massage
                              on_error = on_error,          # Bei Fehler Funktion on_error
                              on_close = on_close)          # Beim schließen Funktion on_close
    ws.on_open = on_open                                    # Beim Start Funktion on_open
    ws.run_forever()

Ausgabe wenn die If Anweisung ausgeführt wird:

**Neues Event ausgelöst**
{'intent': {'name': 'Kodi', 'confidence': 1.0}, 'entities': [{'entity': 'mute', 'value': 'stumm', 'value_details': {'kind': 'Unknown', 'value': 'stumm'}, 'raw_value': 'stumm', 'start': 5, 'end': 10, 'raw_start': 5, 'raw_end': 10}], 'slots': {'mute': 'stumm'}, 'text': 'Kodi stumm', 'raw_text': 'kodi stumm', 'tokens': ['Kodi', 'stumm'], 'raw_tokens': ['kodi', 'stumm'], 'wakeword_id': 'bumblebee', 'siteId': 'default', 'sessionId': 'default-bumblebee-33f1072c-c617-437a-82bd-4779c4f57ad2', 'customData': None, 'wakewordId': 'bumblebee', 'lang': None}
if
stumm

Ausgabe, wenn die else Schleife ausgeführt werden sollte, sie es aber nicht wird:

**Neues Event ausgelöst**
{'intent': {'name': 'Kodi', 'confidence': 1.0}, 'entities': [{'entity': 'pause', 'value': 'Pause', 'value_details': {'kind': 'Unknown', 'value': 'Pause'}, 'raw_value': 'pause', 'start': 5, 'end': 10, 'raw_start': 5, 'raw_end': 10}], 'slots': {'pause': 'Pause'}, 'text': 'Kodi Pause', 'raw_text': 'kodi pause', 'tokens': ['Kodi', 'Pause'], 'raw_tokens': ['kodi', 'pause'], 'wakeword_id': 'bumblebee', 'siteId': 'default', 'sessionId': 'default-bumblebee-f44ff2c4-e1f3-483d-be00-85868f4cba2c', 'customData': None, 'wakewordId': 'bumblebee', 'lang': None}

Zusätzlich hätte ich noch eine Frage:
Warum kann ich den Part " entities': [{'entity': 'pause'" nicht für einen Vergleich nutzen? if "pause" == data["entities"]["entitiy"]: - funktioniert gar nicht.

Wäre für jeden Tipp dankbar, weil ich halt eben auch keinen Fehler bekomme, an den ich mich ab arbeiten könnte.
Mein nächster Schritt wäre sonst, das Ganze noch mal in klein nachzubauen, wäre aber halt viel Arbeit.

PS. Es liegt bestimmt daran, dass beim zweiten Event, slots mute nicht existiert, aber dann müsste die if Anweisung doch false sein und else müsste ausgeführt werden!?!? Oder läuft die if Anweisung auf Fehler und deshalb wird else gar nicht beachtet?
Ich bekomme Kopfweh! :D
Sirius3
User
Beiträge: 14594
Registriert: Sonntag 21. Oktober 2012, 17:20

Samstag 14. November 2020, 23:57

Im zweiten Fall hat data["slots"] keinen Schlüssel "mute" was zu einem KeyError führt, der irgendwo wohl im Eventloop verschluckt wird.
data["entities"] ist eine Liste, die erwartete als Index eine Zahl und keinen Schlüssel.
Miliano
User
Beiträge: 8
Registriert: Samstag 14. November 2020, 20:40

Sonntag 15. November 2020, 01:15

Und wenn dieser Key Error auftritt, dann wird die Schleife nicht weiter ausgeführt? Also deshalb kommt er nicht bis zu else?
Ist ja fies, dass er da keinen Fehler ausspuckt.

Ja, Miste ... [ ] Liste ...
Leider steckt in der Liste alles in einem Element, müsste ich also erst wandeln.
Aber okay, damit kann ich arbeiten. :D

Falls noch wer nen Tipp hat, wie ich das else "Problem" lösen kann, ohne jedes Mal alle möglichen Lösung (was am Ende echt viele werden) gegenzuprüfen, immer her damit.

Aber das mache ich besser Morgen ;)
Benutzeravatar
__blackjack__
User
Beiträge: 8716
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Sonntag 15. November 2020, 01:23

@Miliano: Du solltest auf jeden Fall schauen wo Fehlermeldungen bei Ausnahmen landen. Irgendeine Protokolldatei oder so. Ohne diese Informationen kann man ja kein Programm entwickeln wenn man Ausnahmen nie zu Gesicht bekommt.
long long ago; /* in a galaxy far far away */
Sirius3
User
Beiträge: 14594
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 15. November 2020, 07:48

Um Fehler zu sehen, musst Du das Logging einschalten:

Code: Alles auswählen

logging.basicConfig(level=logging.DEBUG)
Miliano
User
Beiträge: 8
Registriert: Samstag 14. November 2020, 20:40

Sonntag 15. November 2020, 17:21

Hab das ganze jetzt so gelöst:

Code: Alles auswählen

data = str(data)
        einzeldaten = data.split(" '")
        einzeln = einzeldaten[6]
        if "stumm'," == einzeln:
            print("if")
        else:
            print("else")
Sicher nicht die schönste / sauberste Lösung, aber es funktioniert und ist beliebig erweiterbar ...

Danke für die Denkanstöße!

Das mit dem Logging verstehe ich nicht ganz, wann wird denn da was geloggt?
Hab da kurz zu nachgelesen, hat aber eher zu weniger als mehr Verständnis geführt.

Wenn ihr noch Tipps habt, zu meinen Problemen oder auch allgemein, womit man sich beschäftigen sollte, immer gerne! :)
Schönen Sonntag noch!
Mili
Benutzeravatar
__blackjack__
User
Beiträge: 8716
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Sonntag 15. November 2020, 18:05

@Miliano: Das ist nicht nur unschön oder unsauber sondern fehlerhaft. JSON garantiert keine Reihenfolge der Schlüssel/Wert-Paare, das heisst das die magische 6 da ”funktioniert” ist Zufall und kann sich jederzeit ändern. Zumal es auch sonst schon so unschön ist, dass ich von falsch sprechen würde eine Datenstruktur in eine Zeichenkette umzuwandeln statt mit der Struktur zu arbeiten wie das gedacht ist und sauber und sicher funktioniert.
long long ago; /* in a galaxy far far away */
Miliano
User
Beiträge: 8
Registriert: Samstag 14. November 2020, 20:40

Sonntag 15. November 2020, 20:19

Mir ist schon klar, das Json keine Reihenfolge garantiert, aber in diesem speziellen Fall, funktioniert das sehr wohl, da das Ergebnis/ die Ausgabe ja immer die Gleiche ist.

Natürlich verstehe ich was du meinst.

Leider waren die bisherigen Hilfen hier, immer nur was falsch ist, aber kein Tipp, wie ich es anders lösen könnte.
Da bleibt mir leider nichts anderes, als eine "fehlerträchtige" aber funktionierende Lösung zu nutzen, die ich mit meinem Wissen aktuell umsetzen kann, um dann vielleicht später mal besser zu wissen, wie es geht.

Sorry, aber konstruktive Kritik sieht anders aus :(
Benutzeravatar
__blackjack__
User
Beiträge: 8716
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Sonntag 15. November 2020, 22:03

@Miliano: Wenn Du glaubst die magische 6 sei kein Problem dann hast Du nicht verstanden was das Problem ist. Die Schlüssel/Wert-Paare müssen nicht immer in der gleichen Reihenfolge kommen. Das ”funktioniert” halt nur zufällig und damit funktioniert es nicht wirklich.

Wie sieht denn konstruktive Kritik aus? Eine vorgekaute Lösung? Selber damit beschäftigen geht nicht? Konstruktiv: Arbeite das Grundlagentutorial in der Python-Dokumentation durch. JSON wird auf Python-Grunddatentypen abgebildet. Damit muss man umgehen können wenn man etwas in Python programmieren will und das zu lernen kann niemand anderes für Dich machen. Da musst Du selbst durch.
long long ago; /* in a galaxy far far away */
Sirius3
User
Beiträge: 14594
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 15. November 2020, 22:09

Du willst auf einen Schlüssel zugreifen, der nicht existiert. Da wäre die erste Frage, was du eigentlich statt dessen willst. Du hast nur gefragt, warum der else-Block nicht betreten wurde.
Du hast also Events und verschiedene Events haben unterschiedliche Slots.
Ich kenne dieses System nicht, kann also nicht sagen, ob es der richtige Weg ist zu prüfen ob ein Slot da ist oder nicht.
Sollte das der richtige Weg sein, dann sieht die if- Abfrage so aus:

Code: Alles auswählen

if "mute" in data["slots"]:
Benutzeravatar
pillmuncher
User
Beiträge: 1266
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Sonntag 15. November 2020, 22:23

@Miliano: Du hast keinen Anspruch darauf, dass man dir sagt, was du hören willst. Hier im Forum bekommst du aber immer die Antwort, die du hören solltest, zB. diese hier:

dicts haben eine .get()-Methode, der man einen Defaultwert mitgeben kann, der verwendet wird, falls der gesuchte Wert nicht existiert.

Code: Alles auswählen

>>> pprint.pprint(data)
{'customData': None,
 'entities': [{'end': 10,
               'entity': 'pause',
               'raw_end': 10,
               'raw_start': 5,
               'raw_value': 'pause',
               'start': 5,
               'value': 'Pause',
               'value_details': {'kind': 'Unknown', 'value': 'Pause'}}],
 'intent': {'confidence': 1.0, 'name': 'Kodi'},
 'lang': None,
 'raw_text': 'kodi pause',
 'raw_tokens': ['kodi', 'pause'],
 'sessionId': 'default-bumblebee-f44ff2c4-e1f3-483d-be00-85868f4cba2c',
 'siteId': 'default',
 'slots': {'pause': 'Pause'},
 'text': 'Kodi Pause',
 'tokens': ['Kodi', 'Pause'],
 'wakewordId': 'bumblebee',
 'wakeword_id': 'bumblebee'}
>>> data['slots']['mute']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'mute'
>>> data['slots'].get('mute', None)
>>> data['slots'].get('mute', None) == 'stumm'
False
Statt also irgendwas mit fixen Indizes zu basteln, lieber mal in die Doku schauen, ob du dort was findest, was dein Problem löst. Das kannst du aber nur, wenn du dein Problem auch verstehst. Kommentare im Code, die einfach nochmal in Deutsch wiederholen, was da bereits in Python steht, helfen niemandem beim Verstehen, sondern machen alles nur unübersichtlich. Kommentare sind dazu da, zu erklären, warum der Code so dasteht und was du dir dabei gedacht hast, ihn so hinzuschreiben. Weiters macht es auch mehr Spaß, sich mit deinem Code auseinanderzusetzen, wenn man ihn nicht erst selber aufräumen muss. Guckstu:

Code: Alles auswählen

import websocket
import requests
import json
import time
import pprint

from matrix_lite import led


TEXT_TO_SPEECH_URL = 'http://localhost:12101/api/text-to-speech'


def say(text):
    requests.post(TEXT_TO_SPEECH_URL, text.encode('utf-8'))


def on_message(ws, message):
    data = json.loads(message)
    print('**Neues Event ausgelöst**')
    pprint.pprint(data)
    key = data['intent']['name']
    if key == 'Led'
        led.set(data['slots']['color'])
        say('Setze Licht auf: ' + data['slots']['color'])
    elif key == 'Hallo'
        say('Hallo')
    elif key == 'Datum'
        say(time.strftime('%d.%m.%Y'))
    elif key == 'Uhr'
        say(time.strftime('%H:%M'))
    elif key == 'Kodi'
        if data['slots']['mute'] == 'stumm':
            print('if')
            pprint.pprint(data['slots']['mute'])
        else:
            print('else')


def on_error(ws, error):
    print(error)

def on_open(ws):
    print('\n**Verbindung aufgebaut**\n')

def on_close(ws):
    print('\n**Verbindung beendet**\n')


if __name__ == '__main__':
    ws = websocket.WebSocketApp(
            'ws://localhost:12101/api/events/intent',
            on_message=on_message,
            on_error=on_error,
            on_open=on_open,
            on_close=on_close,
    )
    ws.run_forever()
Du führst übrigens lokale Variablen ein, die niemand braucht und lässt sie weg, wo sie sinnvoll wären. Das habe ich geändert. Ellenlange Zeilen sind auch Mist. Verwende Konstanten statt magischer Strings, wie zB. TEXT_TO_SPEECH_URL oben.

Den Tipp mit der dict.get()-Methode bitte selber auf den Code anwenden.
In specifications, Murphy's Law supersedes Ohm's.
Miliano
User
Beiträge: 8
Registriert: Samstag 14. November 2020, 20:40

Sonntag 15. November 2020, 23:06

1. Nein, es geht mir nicht um eine fertige Lösung, sondern um einen Ansatzpunkt, so wie ich ihn aus der letzten Antwort herauslesen kann und mit der ich mich dann beschäftige.
2. Ich habe ein Tutorial durchgearbeitet, nur leider ist es eben nicht so, das man sich direkt alles merken oder richtig anwenden kann. Nur weil man ein Englisch Buch durcharbeitet, kann man auch nicht direkt Englisch sprechen. Aber egal ... das führt zu nichts.

@ pillmuncher - Sorry wegen des unsauberen Codes. Ich verstehe, dass das nur zusätzliche Arbeit macht. Die Kommentare waren nur für mich zum Verständnis, weil ich das aus einem anderen Script übernommen hatte und wissen wollte, was wo passiert, aber klar, dass ihr das nicht braucht.
Danke für den Ansatzpunkt, ich werde mich damit beschäftigen, um nach Möglichkeit daraus zu lernen.

Ich weiß, es ist schwer und nervt, wenn immer wieder Anfänger (wie ich) Grundlagen nicht kennen, aber man muss doch erstmal anfangen.
Ich habe nicht hier geschrieben, weil ich zu faul zum lesen oder testen war, sondern weil ich einfach den Fehler nicht selbst gefunden habe und mir Hilfe erhoffte.
Antworten