Allgemeines Vorgehen - Dictionary?

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.
Camu
User
Beiträge: 31
Registriert: Dienstag 26. September 2017, 08:32

Hallo zusammen,

folgendes Problem wo ich momentan noch am überlegen bin wie ich am besten vorgehe. Verkürzt soll es Datei (welche es immer neu gibt) geben welche Python einlesen soll. Mit diesen Angaben soll dann das Programm arbeiten. Im Endeffekt Variablen aus der Konfig-Datei im Hauptprogramm nutzen. Bis jetzt ist die Konfig-Datei noch flexibel in der Gestaltung, auch das Format. Im groben wird sie aber diesen Inhalt haben.

Code: Alles auswählen

global_start
index1, antwort1
index2, antwort2
...
global_end

Code: Alles auswählen

def_begin
def1, name, table, ...
def2, name, table, ...
def_end
Wenn ich jetzt nur den globalen Teil hätte wäre ja ein Dictionary vielleicht ganz passend. Aber was mache ich mit def-Teil? Oder befinde ich mich ganz auf dem Holzweg? :)

Danke für eure Hilfe
Camu
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Die passende Datenstruktur hängt natürlich von der Struktur der Daten ab. Und da wird man bei der Beschreibung der Konfig-Datei nicht schlau drauß. Was ist denn def1, name, table, ...?
Du musst doch wissen, wie man auf die Werte zugreifen können kann und wie die Struktur aussieht. Du willst ja damit arbeiten.

Ich kenne solche gruppierten Konfigurationen aus uralten DOS-Zeiten und mit etwas Glück gibt es schon einen passenden Parser.
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Camu: Wenn das Format noch nicht festgelegt ist, dann schau Dir doch mal was an was es schon gibt, bevor Du ein neues Format erfindest. JSON beispielsweise.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Camu
User
Beiträge: 31
Registriert: Dienstag 26. September 2017, 08:32

@sparrow Wie gesagt das Format ist noch nicht festgelegt. Im ersten Entwurf hab ich für mich erstmal eine csv Datei gebastelt.

Als Beschreibung des Inhaltes hab ich hier jetzt nur Beispielhafte Namen verwendet. In dem globalen Bereich steht zum Beispiel target_db = xyc. Das def1 ist dann praktisch ein Schlüsselwort was dann mehrere Eigenschaften hat. Ich weiß halt wie gesagt noch nicht wie ich es am besten anstelle :)

@__blackjack__ an JSON oder XML hatte ich auch schon gedacht. Kenne mich damit aber nicht wirklich aus, wobei ich denke das JSON nicht so schwer aussieht.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn du nur im ungefähren bleibst, was genau darin stehen soll, dann kann man auch nur schwammig bei den Vorschlägen sein. Warum die Geheimniskrämerei?
Camu
User
Beiträge: 31
Registriert: Dienstag 26. September 2017, 08:32

Momentan ist es eine csv Datei, welche dann der Nutzer ausfüllt (der Einfachheit halber in Excel zusammengestellt) die wie folgt ausschaut:

Zuerst der "globale" Teil mit einigen Beispielen

Code: Alles auswählen

global_begin;;;
srcdb_port;1433;;
srcdb_name;stuetz;;
...
global_end;;
Als nächstes dann der Defintionsteil, hier fehlt mir noch die springende Idee - momentan habe ich da noch eine Überschrift für die Spalten

tgt_name; src_name; tgt_tbl, src_tbl <-- wäre die Bezeichnung der "Spalten"

Code: Alles auswählen

def_begin;;;
abs; sad; asd; asd;
sds; sds; wew; sad;
...
def_ende;;;
Das jetzt nur ein Auszug, beim globalen Teil kommen noch mehr Zeilen aber immer nur mit einem Paar an Werten, bei den Definitionen noch mehr "Spalten" und natürlich Zeilen.
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Du hast also zwei Teile, einen Key-Value-Teil und einen Tabellen-Teil?
Warum muß das in eine Datei?
Ein Beginn und End ist eigentlich auch nicht nötig, sondern nur eine Trennzeile.
Also einen Key-Value-Reader, der am Trennzeichen aufhört und danach einen csv-Reader.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Oder eine JSON-Datei mit einer Liste von Objekten.

Code: Alles auswählen

[
     {
         "srcdb_port": 1433,
         ...
         "thingies": [
               {
                    ...
               },
              {
                    ...
              }
         ]
     }
]
Camu
User
Beiträge: 31
Registriert: Dienstag 26. September 2017, 08:32

@Sirius - Ja momentan hab ich diese Struktur mir vorgestellt, momentan bin ich mir nämlich auch noch nicht sicher ob der Standarduser den ersten Teil überhaupt sehen soll / diesen überhaupt versteht. Dementsprechend spricht eigentlich auch nichts dagegen das ganze in zwei Dateien zu schreiben.

Angenommen es werden zwei Teile. Dann könnte ich ersten Teil mit Key-Value Werten in ein Dictionary schreiben und den zweiten Teil mit einem csv-Reader einlesen. Da bin ich mir aber noch nicht sicher ob dann auch Dictionary, spricht ja aber eigentlich nichts dagegen oder?

JSON wäre natürlich eine Idee, aber gibt es dafür Editoren / Vorlagen für den Nutzer der "nur" mit Office arbeitet und sich auskennt. Den zweiten Teil soll er nämlich ausfüllen.

Danke für eure Hilfe bisher :)
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

JSON ist schwierig von Hand zu editieren. Ein einfaches Key=Value wäre da leichter.
Camu
User
Beiträge: 31
Registriert: Dienstag 26. September 2017, 08:32

Hallo zusammen,

ich habe nun folgenden Code um die csv in ein Dictionary einzulesen:

Code: Alles auswählen

out_dict = {}  # Dictionary für alle Werte
_file_part = None  # Wertespeicher

with open("test1.csv", "r") as file:
    for line in file:
        line = line.rstrip("\n").rstrip(";") #Zeilenumbruch und Kommas am Ende der Zeile entfernen
        #if Anweisung der verschiedenen Blöcke, Start mit _begin Ende mit _end        
        if line.endswith("_begin"):
            _file_part = line
        elif line.endswith("_end"):
            _file_part = None
        else:
            key, *values = line.split(";") #Zuweisung Key - Values, Delimiter = ;
            out_dict.setdefault(_file_part, {}).update({key: values})

Soweit funktioniert das ganze auch. Jetzt habe ich aber das Problem das man Blöcke (die mit _begin Beginnen und _end enden) eine unterschiedliche Anzahl an Values haben. Zum Beispiel sieht die csv wie folgt aus:

Code: Alles auswählen

part1_begin;
k1;v1
k2;v2
k3;v3
part1_end;
part2_begin;;
k4;v4;v6
k5;v6;v7
k6;v8;v9
part3_end;;
Nun werden die Values für das Dcitionary ja aber immer in Listen gespeichert (egal ob 1 oder mehrere Values). Wie könnte ich am besten vom ersten Block die Values nicht als Liste speichern? Oder gibt es eine Methode die Liste umzuwandeln das nur ein Value drin steht wenn es nur eines gibt? Hoffe konnte es halbwegs verständlich formulieren.

Viele Grüße
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn es sich um eine csv-Datei handelt, warum benutzt Du dann nicht das csv-Modul? Variabelnamen die mit einem _ anfangen, zeigen dem Leser, dass an der Stelle zwar ein Rückgabewert erwartet wird, der aber nicht weiter verwendet wird. Bei Dir ist das mit _file_part nicht der Fall. Bisher hat es sich für mich so angehört, als ob Du einen Teil mit key-Values hast und einen mit nur Werten. Jetzt hat der zweite Teil auch Keys. Was bedeuten denn dort die Schlüssel und warum gibt es mehrere Werte?

Gibt es auch einen part3?
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Der Part 2 beginnt und endet nie, der Part 3 beginnt nie und endet nur.
Das zeigt auch schon die Schwäche des Formats. Oder des Parsers. Denn wenn man den Namen beim _end eh ignoriert, kann man ihn auch weg lassen. Ich würde das mit dem _begin und dem _end lassen, Blöcke mit Leerzeilen trennen und in die erste Zeile des Blocks den Namen schreiben.
Ich finde das aber noch immer sehr skurril und bin mir sicher, dass es da auch ein besser geeignetes Format gibt.

Das verwenden von "update" auf dem dict ist unnötig, da hier eine einfache Wertzuweisung erfolgt. Und die nimmt man bekanntlich mit dict[key] = value vor.

Die Anzahl der Werte in values kann man prüfen und dann entscheiden, wie man mit denen weiter verfährt.
Camu
User
Beiträge: 31
Registriert: Dienstag 26. September 2017, 08:32

Ingesamt habe ich 3 Parts genau (hatte nur die csv verkürzt hier fürs Forum). Part 1 & 2 haben Key - Value. Part 3 ist eher eine Tabelle, da hatte ich mir gedacht das ich dann das Dict in ein Dataframe einlese. So sieht die csv Datei aus nur das Part 3 noch mehr v´s stehen.

Code: Alles auswählen

part1_begin;
k1;v1
k2;v2
k3;v3
part1_end;
part2_begin;;
k4;v4
k5;v6
k6;v8
part2_end;
part3_begin;;;
v10;v11;v12;v13
v14;v15;v16;v17
part3_end;;;
@Sparrow, ja war Schreibfehler von mir mit Part2 und Part3 in dem Beispiel. Leider ist das mit dem _begin und _end momentan eine Vorgabe (begeistert bin ich von der Lösung auch nicht). Aber Deine Idee mit der Leerzeile und dem Namen in der ersten Zeile dann kann ich natürlich mal vorschlagen.

Aber da könnte ich ja eigentlich im Endeffekt in der if Abfrage abfragen welcher Part kommt, dann die entsprechende Zuweisung bei Part 1 und 2 in ein Dictionary und beim dritten Part gleich das ganze in ein Dataframe setzen oder?
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Jetzt gibt es in Part 2 gar keine mehreren Values mehr dafür aber in Part 3 keine Keys? Dann ist dein Problem ja schon ein ganz anderes als noch im letzten Post. Vielleicht solltest du dein Format erst einmal fertig spezifizieren?
Ob das Einlesen in ein Dataframe nützlich ist, kann man nicht sagen, ohne zu wissen, was mit den Daten geschehen soll. Für 2 Zeile á 4 Werten lohnt sich das auf jeden Fall nicht.
Camu
User
Beiträge: 31
Registriert: Dienstag 26. September 2017, 08:32

So wie es jetzt als letztes steht sieht die Datei aus, bis auf das Part3 Stand jetzt circa 20 "Spalten" hat und die Anzahl der Zeilen ist unbekannt. Kann aber bis in die 1000 gehen. Die Werte in Part 3 sollen in verschiedene Datenbankabfragen eingebaut werden.
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Dann hast Du also zwei Key-Value-Blöcke und ein Datenfeld. Diese würde ich auch getrennt behandeln.
Camu
User
Beiträge: 31
Registriert: Dienstag 26. September 2017, 08:32

Genau.

Momentan hänge ich dann aber an der if-Abfrage. Zuerst schaue ich ob Part1 in der Zeile steht, schreibe dann die Zeilen ins Dictionary. Wie schreibe ich dann das Abbruchkriterium wenn das zum Beispiel die Leerzeile ist?

Ich würde dann einfach 3 if-Abfragen machen und für die ersten beiden Parts jeweils in ein Dict und dritten Part dann in ein Dataframe oder eventuell was anderes.
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Du hast dann 3 for-Schleifen, die jeweils an der Trennzeile abbrechen. Wenn die ersten beiden Blöcke gleichartig sind, dann natürlich zweimal die selbe Funktion aufrufen.
Camu
User
Beiträge: 31
Registriert: Dienstag 26. September 2017, 08:32

Ich steh momentan total auf dem Schlauch :( bisher habe ich nur

Code: Alles auswählen

with open ('test1a.csv', 'r', newline='') as csvfile:
    for line in csvfile:
        if 'part1' in line:
            reader = csv.reader(csvfile, delimiter=';')
            part1_dict = dict(reader)

Aber wie ich denn Abbruch machen könnte weiß ich nicht, schon überlegt ob ich Zeilenlänge zähle.
Antworten