Verschachtelte json Daten iterieren.

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
ahupfer
User
Beiträge: 23
Registriert: Mittwoch 15. August 2018, 07:24

Hallo Zusammen,

Aufgabenstellung:
Ich möchte gerne aus einer json Datei mit einer Verzeichnisstruktur Verzeichnisse in einem Projektorder erstellen.
Dazu habe ich eine Klasse Folder mit einer Methode create_folder erstellt.
Über ein Script lese ich das json File ein, erstelle Objekte der Klasse Folder und erstelle die Verzeichnisse, was auch
prima klappt. Da die Verzeichnisse theoretisch beliebig viele Unterverzeichnisse haben können, bin ich mir nicht sicher
wie ich solch 'komplexe' Strukturen entwirren kann? In meinem Script schaffe ich es ja nur bis zu den ersten Unterverzeichnissen.

Frage: Wie kann ich beliebig verschachtelte Datenstrukturen in json iterieren?

Ich bin noch Python Anfänger und möchte gerne etwas lernen, darum habe ich auch eine eigene Klasse dafür erstellt, ich weiss
über ein einfaches Script mit Funktionen wäre es vermutlich einfacher.
Ich weiss auch gar nicht wo nach ich googeln soll? Evtl. könnt ihr mir ein bisschen auf die Sprünge helfen bzw. Tipps geben.
Es muss auch keine fertige Lösung sein.

Hier meine json Datei:

Code: Alles auswählen

[
  {
    "name": "Finanzen",
    "path": "",
    "children": [ { "name": "Jahresabschluesse",
                    "path": "Finanzen\\Jahresabschluesse"},
                  {"name": "Nebenkostenabrechnungen",
                    "path": "Finanzen\\Nebenkostenabrechnungen"}
                ]
  },
  {
    "name": "Korrespondenz",
    "path": "",
    "children": [
        {
          "name": "Mieter",
          "path": "Korrespondenz\\Mieter"
        }
      ]
  },
  {
    "name": "Mieter",
    "path": "",
    "children": []
  },
  {
    "name": "Objekte",
    "path": "",
    "children": []
  }
]
Die Klasse Folder

Code: Alles auswählen

import os

class Folder:
    def __init__(self, name, path, children=[], proj_folder=None):
        self.name = name
        self.path = path if path != "" else name
        self.children = children

    def create_folder(self, proj_folder="prj"):
        try:
            os.makedirs(os.path.join(proj_folder, self.path))
        except OSError as e:
            print(e)
Das Script

Code: Alles auswählen

import json,os
from folder import Folder

with open('json/ver_folder_struc.json', 'r') as f:
    folders = json.load(f, encoding='UTF-8' )

for i in folders:
    # Create rootfolders
    folder = Folder(**i)
    folder.create_folder()
    # Create subfolders 
    if folder.children:
        for chield in folder.children:
            subfolder = Folder(**chield)
            subfolder.create_folder()


Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ahupfer: Eine sinnlose Klasse, die eigentlich nur eine Funktion wäre, mit der Begründung zu schreiben, dass man als Anfänger etwas lernen will ist seltsam. Denn wichtig zu lernen im Zusammenhang mit Klassen ist auch und gerade wann man sie einsetzt und wann nicht.

Wenn eine Klasse aus einer `__init__()` und nur einer weiteren Methode besteht, ist das meistens eine umständlich geschriebene Funktion. Wenn die Verwendung dann immer aus Exemplar erstellen, gleich darauf die einzige Methode aufrufen, und danach das Exemplar nicht wieder verwenden besteht, dann ist das sehr sicher einfach nur eine Funktion. Und man lernt auch nichts dabei das umständlich als Klasse zu schreiben.

Warum ist die Klasse in einem eigenen Modul?

Die Datenstruktur sieht redundant aus was 'name' und 'path' angeht wenn der Namen immer wenn 'path' nicht leer ist, als letztes noch mal den 'name'-Wert enthält.

Über eine rekursive Datenstruktur geht man am einfachsten mit einer rekursiven Funktion. Dann ist die auch gar nicht komplex, denn man muss ja immer nur ein (Teil)Objekt aus 'name', 'path', und 'children' betrachten. Wobei es wahrscheinlich besser/einfacher/konsequenter wäre, wenn es 'children' tatsächlich auch immer geben würde. Und nicht mal ja, selbst wenn es ein leeres Array als Wert gibt, und mal nicht.

Bei der Klasse wird das Argument `children` mit einer leeren Liste als Default-Wert belegt. Das ist potentiell gefährlich weil das *eine* Liste ist, die für alle Exemplare von `Folder` die selbe ist. Wenn man da einfach nur ein leeres iterierbares Objekt als Default haben möchte, wäre ein leeres Tupel sicherer.

Mit dem `proj_folder`-Argument wird in der `__init__()` gar nichts gemacht‽

Backslash als Pfadtrenner ist doof. IMHO.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

Rekursive Strukturen arbeitet man am einfachsten mit einer rekursiven Funktion ab:

Code: Alles auswählen

from pathlib import path

def create_folder(path, children=[]):
    path.mkdir(parents=True, exists_ok=True)
    for entry in children:
        create_folder(path / entry['name'], entry.get('children', []))

entries = [
  {
    "name": "Finanzen",
    "children": [ {"name": "Jahresabschluesse"},
                  {"name": "Nebenkostenabrechnungen"}
                ]
  },
  {
    "name": "Korrespondenz",
    "children": [ {"name": "Mieter" }]
  },
  {"name": "Mieter"},
  {"name": "Objekte"}
]

create_folder(Path('prj'), entries)
ahupfer
User
Beiträge: 23
Registriert: Mittwoch 15. August 2018, 07:24

Hallo

Vielen Dank für die beiden Antworten. Ich habe mich mit den rekursive Funktionen auseinandergesetzt und
dabei einen fundamentalen Gedankenfehler bezüglich der Programmierung bei mir eindeckt und begriffen!
Vielen Dank dafür!!! Es ist etwas peinlich aber ich dachte beim ersten rekursiven Aufruf der Funktion wird die
'for' Schleife unterbrochen, die läuft im Hintergrund ja weiter! :?
Ich werde das ganze, dann mit Funktionen lösen und die Klasse weglassen.

Beste Grüsse und nochmals vielen Dank!
Andreas
Tholo
User
Beiträge: 177
Registriert: Sonntag 7. Januar 2018, 20:36

__blackjack__ hat geschrieben: Donnerstag 28. März 2019, 14:05 Wenn eine Klasse aus einer `__init__()` und nur einer weiteren Methode besteht, ist das meistens eine umständlich geschriebene Funktion. Wenn die Verwendung dann immer aus Exemplar erstellen, gleich darauf die einzige Methode aufrufen, und danach das Exemplar nicht wieder verwenden besteht, dann ist das sehr sicher einfach nur eine Funktion.
Kann man das irgendwie Anpinnen? Die Umschreibung find ich sehr gut

@BJ
Nimm das mal in deine makro Liste auf :P
Antworten