mehrere dict nacheinander nach Keys durchsuchen.

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.
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

Hallo,

ich hätte ein kleines Problemchen.

Folgendes möchte ich realisieren.
In einem Geber können bis zu vier Fehlernummern hinterlegt sein.
Laut Beschreibung, können diese nacheinander ausgelesen werden.
Also dachte ich mir, ich bastle mir ein dict in denen die Fehlerbereiche aufgetrennt werden und ein dict_ fehler_request sendet mir die 4 zu erhaltenen Fehlermeldungen zurück.

Das Dict muss also dynamisch erstellt werden. Geht so etwas?
Meine Versuche sind nicht zielführend.

Kann sich einer mich annehmen?

Gruß Ralf

Code: Alles auswählen

import sick_error

fehlercode = "01" # Beispiel für Fehlercode

print(sick_error.sks_skm(fehlercode))


Code: Alles auswählen

#Datei sick_error


def sks_skm(a):
    initialisierung = {
        "00" :"der Geber hat keinen fehler erkannt",
        "01" :"abgleichdaten fehlerhaft",
        "02" :"interner Winkeloffset fehlerhaft",
        "03" :"tabelle über datenfeldpartitionierung zerstört",
        "04" :" analoge grenzwerte nicht verfügbar",
        "05" :"interner i2c-Bus nicht funktionsfähig",
        "06" :"interner checksummenfehler"             
        }

  
    protokoll = {
        "07":" geberreset durch Programmüberwachung aufgetreten",
        "09":" Parityfehler",
        "0a":" checksumme der übertragenen daten ist falsch",
        "0B" :"unbekannter Befehlscode",
        "0c" :"anzahl der übertragenen daten ist falsch",
        "0d" :"übertragenes Befehlsargument ist unzulässig",
        }
  
    daten = {
        "0e" :"das selektierte datenfeld darf nicht beschrieben werden",
        "0f":"falscher Zugriffscode",
        "10":"angegebenes datenfeld in seiner größe nicht veränderbar",
        "11":" angegebene Wortadresse außerhalb datenfeld",
        "12" :"Zugriff auf nicht existierendes datenfeld"
        }
       
    position = {
        "01":"Analogsignale außerhalb Spezifikation",
        "1f":"drehzahl zu hoch, keine Positionsbildung möglich",
        "20":"Position Singleturn unzuverlässig",
        "21":"Positionsfehler multiturn",
        "22":"Positionsfehler multiturn",
        "23":"Positionsfehler multiturn"
        }
    
   
    andere = {
        "1c":"Betragsüberwachung der Analogsignale (Prozessdaten)",
        "1d":"Senderstrom kritisch (Verschmutzung, Senderbruch)",
        "1e":"gebertemperatur kritisch",
        "08":"überlauf des Zählers"
        }   
 
    fehlerbereiche=[
        "initialisierung" ,
        "protokoll" ,
        "daten" ,
        "position" ,
        "andere"
        ]
    
   
    i=0
    
   

    while i <=4:

    	bau mir ein Dict
	

        i = i+1
    

    return fehler_request


kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

Ich hänge hier voll danaben....

warum funktioniert das so nicht?

Code: Alles auswählen


    i=0
    fehlercode = "00"


    while i <4:

        if fehlercode in fehlerbereiche[0].keys():
            ,,,,,
        i = i+1


Fehlermeldung:

if fehlercode in fehlerbereiche[0].keys():
AttributeError: 'str' object has no attribute 'keys'

Ja sicher. das Element aus der Liste hat ja kein key.

fehlerbereiche[0] soll ja mein Dict sein aus dem ich abfrage. :roll:
Benutzeravatar
sparrow
User
Beiträge: 4564
Registriert: Freitag 17. April 2009, 10:28

Das Konstrukt ist in Python auf jeden Fall ein Antipattern:

Code: Alles auswählen

    i=0

    while i <=4:
    	bau mir ein Dict
        i = i+1
Ich verstehe nicht, was "fehlerbereiche" sein soll. Ist das die dynamische Benennung der Namen der Dicts?

Und aus dem Namen der Funktion geht leider auch gar nicht hervor, was da passieren soll. Keine Ahnung welche Buchstaben da bei sks_skm verschluckt wurden. Steht das für Schaukelstuhl Sakrament?
Lange Rede kurzer Sinn: Du solltes das Problem beschreiben, das du lösen möchtest - nicht das, was du für die Lösung hälst. Die Lösung sieht sehr falsch aus.
Benutzeravatar
Dennis89
User
Beiträge: 1616
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

wieso schreibst du das nicht einfach gleich so?

Code: Alles auswählen

def sks_skm(a):
    key_to_value = {
        "initialisierung": {
            "00": "der Geber hat keinen fehler erkannt",
            "01": "abgleichdaten fehlerhaft",
            "02": "interner Winkeloffset fehlerhaft",
            "03": "tabelle über datenfeldpartitionierung zerstört",
            "04": " analoge grenzwerte nicht verfügbar",
            "05": "interner i2c-Bus nicht funktionsfähig",
            "06": "interner checksummenfehler",
        },
        "protokoll": {
            "07": " geberreset durch Programmüberwachung aufgetreten",
            "09": " Parityfehler",
            "0a": " checksumme der übertragenen daten ist falsch",
            "0B": "unbekannter Befehlscode",
            "0c": "anzahl der übertragenen daten ist falsch",
            "0d": "übertragenes Befehlsargument ist unzulässig",
        },
        "daten": {
            "0e": "das selektierte datenfeld darf nicht beschrieben werden",
            "0f": "falscher Zugriffscode",
            "10": "angegebenes datenfeld in seiner größe nicht veränderbar",
            "11": " angegebene Wortadresse außerhalb datenfeld",
            "12": "Zugriff auf nicht existierendes datenfeld",
        },
        "position": {
            "01": "Analogsignale außerhalb Spezifikation",
            "1f": "drehzahl zu hoch, keine Positionsbildung möglich",
            "20": "Position Singleturn unzuverlässig",
            "21": "Positionsfehler multiturn",
            "22": "Positionsfehler multiturn",
            "23": "Positionsfehler multiturn",
        },
    }
    print(list(key_to_value["initialisierung"].keys()))
Edit: Ah ich glaube ich verstehe, du hast einen Fehlercode, der wird der Funktion als Argument `a` übergeben und die Funktion soll die Beschreibung des Fehlercodes zurück geben und dadurch das ganze Wörterbuch durchsuchen?
"When I got the music, I got a place to go" [Rancid, 1993]
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

Meine Frage wäre:

ich Frage ein Dict mit dict_name(dict_key) ab. Ich erhalte das Value aus dem Wert. Richtig?
Wie könnte ich den Nahmen des Dict durch ein dynamischen Namen ersetzen. eventuell aus einer Liste.

also so in etwa:

list_name(i)(dict_key)
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

@Dennis89
Edit: Ah ich glaube ich verstehe, du hast einen Fehlercode, der wird der Funktion als Argument `a` übergeben und die Funktion soll die Beschreibung des Fehlercodes zurück geben und dadurch das ganze Wörterbuch durchsuchen?
Genau.
Ich dachte ich könnte das dict(initialisierung) in print(list(key_to_value["initialisierung"].keys())) dynamisch ersetzen.
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

sparrow hat geschrieben: Samstag 27. September 2025, 19:23 Ich verstehe nicht, was "fehlerbereiche" sein soll. Ist das die dynamische Benennung der Namen der Dicts?
Richtig gedacht.
Benutzeravatar
Dennis89
User
Beiträge: 1616
Registriert: Freitag 11. Dezember 2020, 15:13

Ja.
So:

Code: Alles auswählen

SECTOR_TO_ERROR = {
    "initialisierung": {
        "00": "der Geber hat keinen fehler erkannt",
        "01": "abgleichdaten fehlerhaft",
        "02": "interner Winkeloffset fehlerhaft",
        "03": "tabelle über datenfeldpartitionierung zerstört",
        "04": " analoge grenzwerte nicht verfügbar",
        "05": "interner i2c-Bus nicht funktionsfähig",
        "06": "interner checksummenfehler",
    },
    "protokoll": {
        "07": " geberreset durch Programmüberwachung aufgetreten",
        "09": " Parityfehler",
        "0a": " checksumme der übertragenen daten ist falsch",
        "0B": "unbekannter Befehlscode",
        "0c": "anzahl der übertragenen daten ist falsch",
        "0d": "übertragenes Befehlsargument ist unzulässig",
    },
    "daten": {
        "0e": "das selektierte datenfeld darf nicht beschrieben werden",
        "0f": "falscher Zugriffscode",
        "10": "angegebenes datenfeld in seiner größe nicht veränderbar",
        "11": " angegebene Wortadresse außerhalb datenfeld",
        "12": "Zugriff auf nicht existierendes datenfeld",
    },
    "position": {
        "01": "Analogsignale außerhalb Spezifikation",
        "1f": "drehzahl zu hoch, keine Positionsbildung möglich",
        "20": "Position Singleturn unzuverlässig",
        "21": "Positionsfehler multiturn",
        "22": "Positionsfehler multiturn",
        "23": "Positionsfehler multiturn",
    },
}


def change_names(names):
    return dict(zip(names, SECTOR_TO_ERROR.values()))
        


print(change_names(["a", "b", "c", "d"]))

Willst du das als Ergebnis?

Code: Alles auswählen

SECTOR_TO_ERROR = {
    "initialisierung": {
        "00": "der Geber hat keinen fehler erkannt",
        "01": "abgleichdaten fehlerhaft",
        "02": "interner Winkeloffset fehlerhaft",
        "03": "tabelle über datenfeldpartitionierung zerstört",
        "04": " analoge grenzwerte nicht verfügbar",
        "05": "interner i2c-Bus nicht funktionsfähig",
        "06": "interner checksummenfehler",
    },
    "protokoll": {
        "07": " geberreset durch Programmüberwachung aufgetreten",
        "09": " Parityfehler",
        "0a": " checksumme der übertragenen daten ist falsch",
        "0B": "unbekannter Befehlscode",
        "0c": "anzahl der übertragenen daten ist falsch",
        "0d": "übertragenes Befehlsargument ist unzulässig",
    },
    "daten": {
        "0e": "das selektierte datenfeld darf nicht beschrieben werden",
        "0f": "falscher Zugriffscode",
        "10": "angegebenes datenfeld in seiner größe nicht veränderbar",
        "11": " angegebene Wortadresse außerhalb datenfeld",
        "12": "Zugriff auf nicht existierendes datenfeld",
    },
    "position": {
        "01": "Analogsignale außerhalb Spezifikation",
        "1f": "drehzahl zu hoch, keine Positionsbildung möglich",
        "20": "Position Singleturn unzuverlässig",
        "21": "Positionsfehler multiturn",
        "22": "Positionsfehler multiturn",
        "23": "Positionsfehler multiturn",
    },
}


def get_error(error_code):
    for sector in SECTOR_TO_ERROR.values():
        if error_code in sector:
            print(f"Fehlercode <{error_code}> bedeutet:\n{sector[error_code]}")


get_error("23")
"When I got the music, I got a place to go" [Rancid, 1993]
Sirius3
User
Beiträge: 18306
Registriert: Sonntag 21. Oktober 2012, 17:20

@kiaralle: so wie es Dennis89 doch zeigt, Du packst alle Deine Wörterbücher in eine andere Datenstruktur. Wobei es ja nicht eindeutig ist, weil der selbe Fehlercode in mehreren Fehlerbereichen vorkommt.

Code: Alles auswählen

for fehlerbereich, fehler_bezeichnung in key_to_value.items():
    if fehler in fehler_bezeichnung:
        print(fehlerbereich, fehler_bezeichnung[fehler])
Gewöhn Dir am besten von Anfang an gute Variaben- und Funktionsnamen, `a` ist völlig nichtssagend und was `sks_skm` bedeuten soll, erschließt sich auch nicht.
Benutzeravatar
noisefloor
User
Beiträge: 4216
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

was ist denn ein "dynamischer Name"? Namen sind immer an ein Objekt gebunden, die Bindung kannst du zur Laufzeit ändern. Und du dann mehrere Namen an ein Objekt binden.

Am besten zeigst du mal den Code, den du hast (=der nicht das macht, was du gerne hättest) und schreibst an der Stelle, wo das Programm nicht den von dir gewünschten Wert liefert, dazu, was du da gerne hättest.

Gruß, noisefloor
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

@noisefloor
dynamischer Name" ist ein Überbleibsel von PHP. Da geht so was.

Code: Alles auswählen

Schleife:
  name_$i;
 .....
 $i ++; 
 
name_1, name_2......
Benutzeravatar
noisefloor
User
Beiträge: 4216
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Ok - aber wo brauchst du denn jetzt in Python "dynamische Name"? Bei den Schlüsseln für das neue Dict? Wenn du als Schlüssel eine String nimmst kannst du den String mit den Bordmitteln von Python dynamisch Zusammenbauen.

Gruß, noisefloor
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

@Dennis89
dein zweiter Code kommt meinem Wunsch schon sehr nahe.
Vor allem weil beim Fehlercode "01" der kommt ja zweimal vor, beide Fehler gemeldet werden.
Danke darauf kann ich weiter aufbauen.
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

noisefloor hat geschrieben: Samstag 27. September 2025, 19:55 Ok - aber wo brauchst du denn jetzt in Python "dynamische Name"? Bei den Schlüsseln für das neue Dict? Wenn du als Schlüssel eine String nimmst kannst du den String mit den Bordmitteln von Python dynamisch Zusammenbauen.

Gruß, noisefloor

Daran bin ich ja gescheitert.
Mein Wissensstand ist eben noch sehr mager :D
Benutzeravatar
noisefloor
User
Beiträge: 4216
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Aha... aber das ist doch nicht wirklich anders als in PHP:

Code: Alles auswählen

>>> some_dict = {}
>>> for i in range(1, 4):
...     some_dict[f'key_{i}'] = 'foo'
...
>>> some_dict
{'key_1': 'foo', 'key_2': 'foo', 'key_3': 'foo'}
>>>
Ob das sinnvoll ist, ist ein anderes Thema. Wenn man in Python irgendwas durchnummeriert, dann braucht man i.d.R. eine Liste, worauf man per Index zugreift. Wenn das 2. Beispiel von @Dennis89 fast das macht, was du brauchst, dann hat das aber nix mit dynamischen Namen zu tun. Dann fehlt dir eher noch das Verständnis von passenden Datenstrukturen und Iteration darüber. Iteration ist in Python ziemlich wichtig, weil Python Iteratoren an vielen Stellen unterstützt.

Gruß, noisefloor
Benutzeravatar
sparrow
User
Beiträge: 4564
Registriert: Freitag 17. April 2009, 10:28

@kiaralle: Ich würde das gar nich so machen. Deshalb auch meine Frage, welches Problem du eigentlich lösen willst. Wenn es dir um das Mappen von Fehlercodes auf Fehlermeldungen (also Text) geht, ist das, was du hier versuchst, super kompliziert und wirkt so wie ich das Problem verstehe auch falsch.

Du brauchst auf jeden Fall den Kontext, um eine Fehlermeldung zuordnen zu können. Den hast du aber in deiner Funktion gar nicht. Also rätst du irgendwas.
Woher bekommst du den Kontext? Woher weißt du, dass "01" in den Daten oder in der Initialisierung aufgetreten ist? _Dort_ musst du auf die Meldungen zugreifen. Nicht in einer Funktion in der du das alles zusammenwürfelst.

Deshalb gehen die Vorschläge hier, die das ganz ohne Funktion machen und die Dicts als Konstanten definieren, in meinen Augen eher in die richtige Richtung.
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

Ja, das von Dennis89 ist eine andere Herangehensweise.

"dynamische Name" benötige ich eigentlich nicht. Ist etwas falsch beschrieben.
Ich möchte die das aufzurufende Dict aus einer Liste heraus aufrufen.

Liste ----- > fehlerbereiche=["initialisierung","protokoll","daten","position","andere"] ----> Dict_Name

Ob das jetzt noch Sinnvoll erscheint... Ich weiß es gerade nicht.
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

@sparrow

Du könntest hier etwas rechte haben. Mit meinen doch recht begrenzten Wissen habe ich ein Projekt am laufen, was auch zum Teil schon funktioniert.
Ich rufe von Gebern des Herstellers Sick, Protokoll Hiperface, Daten ab und richte den Geber am Servomotor neu ein. Das läuft super.
Ein Programm habe ich etwas rudimentär mit Tkinter am laufen.

Nun hat jeder Gebertyp seine eigenen Fehlerwerte. Die übernehme ich aus dem jeweiligen Datenblatt des Gebers in dein Typen-gebundenes Dict. Deshalb zum Bleistift srs_skm.
Nach der Abfrage sende ich den Gebertyp und den Fehlercode an meine Lib sick_error.
Ich erhalte die Beschreibung des Fehlercodes.

Jedenfalls habe ich wieder etwas gelernt ;-)
Benutzeravatar
sparrow
User
Beiträge: 4564
Registriert: Freitag 17. April 2009, 10:28

Aber weißt du denn in dem Moment der Abfrage, welchen Gebertyp du ansprichst?
kiaralle
User
Beiträge: 148
Registriert: Donnerstag 19. August 2021, 19:11

sparrow hat geschrieben: Samstag 27. September 2025, 20:32 Aber weißt du denn in dem Moment der Abfrage, welchen Gebertyp du ansprichst?
jo, weiß ich

Am beispiel von denny89 müsste ich etwas ändern.

Warum kann ich für model keinen String übergeben. Oder wie löse ich das?


Code: Alles auswählen

srs_skm = {
    "initialisierung": {
        "00": "der Geber hat keinen fehler erkannt",
        "01": "abgleichdaten fehlerhaft",
        "02": "interner Winkeloffset fehlerhaft",
        "03": "tabelle über datenfeldpartitionierung zerstört",
        "04": " analoge grenzwerte nicht verfügbar",
        "05": "interner i2c-Bus nicht funktionsfähig",
        "06": "interner checksummenfehler",
    },
    "protokoll": {
        "07": " geberreset durch Programmüberwachung aufgetreten",
        "09": " Parityfehler",
        "0a": " checksumme der übertragenen daten ist falsch",
        "0B": "unbekannter Befehlscode",
        "0c": "anzahl der übertragenen daten ist falsch",
        "0d": "übertragenes Befehlsargument ist unzulässig",
    },
    "daten": {
        "0e": "das selektierte datenfeld darf nicht beschrieben werden",
        "0f": "falscher Zugriffscode",
        "10": "angegebenes datenfeld in seiner größe nicht veränderbar",
        "11": " angegebene Wortadresse außerhalb datenfeld",
        "12": "Zugriff auf nicht existierendes datenfeld",
    },
    "position": {
        "01": "Analogsignale außerhalb Spezifikation",
        "1f": "drehzahl zu hoch, keine Positionsbildung möglich",
        "20": "Position Singleturn unzuverlässig",
        "21": "Positionsfehler multiturn",
        "22": "Positionsfehler multiturn",
        "23": "Positionsfehler multiturn",
    },
}


def get_error(model,error_code):
    for sector in model.values():
        if error_code in sector:
            print(f"Fehlercode <{error_code}> bedeutet:\n{sector[error_code]}")
            
model = "srs_skm"
error_code = "00" 
get_error(model,error_code)
Antworten