Eingelesene Dateien aus Json geht verloren

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
Hartmannsgruber
User
Beiträge: 89
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Servus Forum,

ich habe einen für mich unerklärlichen Fehler gefunden.

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import csv
import json
import logging
import os
import platform
import sys
from pathlib import Path
from PyQt5 import uic
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtWidgets import (QAbstractItemView, QApplication, QComboBox,
                             QCompleter, QFormLayout, QHBoxLayout,
                             QInputDialog, QLabel, QLineEdit, QMainWindow,
                             QMessageBox, QPushButton, QTableWidget,
                             QTableWidgetItem, QTextEdit, QTreeView,
                             QVBoxLayout, QWidget)

log_format = "%(levelname)s : %(asctime)s : Zeile: %(lineno)s : %(message)s"
logging.basicConfig(filename="infolog.log", level=logging.INFO,
                    format=log_format)

if platform.system() == "Linux":
    listenpfad = str(Path().absolute()) + "/Listen/"
    grafikpfad = str(Path().absolute()) + "/Grafiken/"
    uipfad = str(Path().absolute()) + "/Ui/"
elif platform.system() == "Windows":
    listenpfad = str(Path().absolute()) + "\\Listen\\"
    grafikpfad = str(Path().absolute()) + "\\Grafiken\\"
    uipfad = str(Path().absolute()) + "\\Ui\\"

zutatendatei = listenpfad + "Zutaten.json"
mengeneinheitendatei = listenpfad + "Mengeneinheiten.csv"

mainwindow_ui = uipfad + "mainwindow.ui"

mengeneinheiten = []
zutaten = {}

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)        
        uic.loadUi(mainwindow_ui, self)
        print(mengeneinheiten)
        print(zutaten)
        
        self.show()


def lade_aus_json(dateiname, zieldatei, loggingbezeichnung):
    with open(dateiname, "r", encoding="utf-8") as jsonfile:
        zieldatei = json.load(jsonfile)
    logging.info("Die " + loggingbezeichnung + " wurde aus der Jsondatei " + \
                    " eingelesen.")

def lade_aus_csv(dateiname, zielliste, loggingbezeichnung):
    with open(dateiname, "r", encoding="utf-8", newline="") as csvfile:
        reader = csv.reader(csvfile, delimiter=";")
        
        [zielliste.append(element[0]) for element in reader]
    logging.info("Die " + loggingbezeichnung + " wurde aus der CSV Datei " + \
                    " eingelesen.")


def main(): 
    lade_aus_json(zutatendatei, zutaten, "Zutaten")
    lade_aus_csv(mengeneinheitendatei, mengeneinheiten, "Mengeneinheiten")
    
    app = QApplication(sys.argv)
    mainwindow = MainWindow()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
Es wird je eine CSV und eine JSON Datei eingelesen.
Die csv Datei erhält die Werte durch die Funktion "lade_aus_csv".
Rufe ich nun Variable in der Instanz der Klasse MainWindow auf, so enthält sie Daten.
Die json Datei erhält die Werte durch die Funktion "lade_aus_json".
Rufe ich aber diese Variable in der Instanz der Klasse MainWindow auf, so ist die Variable ohne Leer.

Warum greift nun genau die Instanz auf die Variable mit den leeren Werten zu und auch nur bei der json Datei?
Bitte um Erklärung.

Liegt in diesen Fall eine harte Kodierung vor, bzw. sind die Pfade richtig als Absolute Pfade gesetzt?

Vielen Dank!
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Du benutzt pathlib.Path stückelst dann aber je nach Betriebssystem Pfade per String+ zusammen. WARUM?
Benutze keine globalen Variablen. Alles was eine Funktion braucht, bekommt sie über ihre Argumente, hier aber: die Ergebnisse liefert sie per `return` zurück.
Listcomprehensions sind KEIN Ersatz für for-Schleifen, wenn mit dem Ergebnis der Liste gar nichts gemacht wird, oder das, was innerhalb passiert Nebeneffekte hat.
Strings setzt man nicht per + zusammen, sondern benutzt format-Strings.
KONSTANTEN schreibt man komplett GROSS.
`zieldatei` wird in `lade_aus_json` als Argument benutzt und nicht verwendet und als Lokale Variable definiert und nicht benutzt. Der Name zieldatei ist auch falsch, da es sich gar nicht um eine Datei handelt.
Fenster sollte sich nicht selbst darstellen, das show gehört aus __init__ raus.

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import csv
import json
import logging
import sys
from pathlib import Path
from PyQt5 import uic
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtWidgets import (QAbstractItemView, QApplication, QComboBox,
                             QCompleter, QFormLayout, QHBoxLayout,
                             QInputDialog, QLabel, QLineEdit, QMainWindow,
                             QMessageBox, QPushButton, QTableWidget,
                             QTableWidgetItem, QTextEdit, QTreeView,
                             QVBoxLayout, QWidget)

LOG_FORMAT = "%(levelname)s : %(asctime)s : Zeile: %(lineno)s : %(message)s"
LOG_FILENAME = "infolog.log"

BASE_PATH = Path().absolute()
LIST_PATH = BASE_PATH / "Listen"
GRAPHICS_PATH = BASE_PATH / "Grafiken"
UI_PATH = BASE_PATH / "Ui"
ZUTATEN_PATH = LIST_PATH / "Zutaten.json"
MENGENEINHEITEN_PATH = LIST_PATH / "Mengeneinheiten.csv"
MAINWINDOW_UI = UI_PATH / "mainwindow.ui"

class MainWindow(QMainWindow):
    def __init__(self, mengeneinheiten, zutaten):
        QMainWindow.__init__(self)        
        uic.loadUi(MAINWINDOW_UI, self)
        print(mengeneinheiten)
        print(zutaten)

def lade_aus_json(dateiname, loggingbezeichnung):
    with open(dateiname, encoding="utf-8") as jsonfile:
        result = json.load(jsonfile)
    logging.info(f"Die {loggingbezeichnung} wurde aus der Jsondatei eingelesen.")
    return result

def lade_aus_csv(dateiname, loggingbezeichnung):
    with open(dateiname, encoding="utf-8", newline="") as csvfile:
        reader = csv.reader(csvfile, delimiter=";")
        result = [element[0] for element in reader]
    logging.info(f"Die {loggingbezeichnung} wurde aus der CSV Datei eingelesen.")
    return result

def main(): 
    logging.basicConfig(filename=LOG_FILENAME, level=logging.INFO, format=LOG_FORMAT)
    zutaten = lade_aus_json(ZUTATEN_PATH, "Zutaten")
    mengeneinheiten = lade_aus_csv(MENGENEINHEITEN_PATH, "Mengeneinheiten")
    app = QApplication(sys.argv)
    mainwindow = MainWindow(mengeneinheiten, zutaten)
    mainwindow.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
Normalerweise möchte man Dateien nicht relativ zum aktuellen Arbeitsverzeichnis ablegen, sondern relativ zur Pythondatei:

Code: Alles auswählen

BASE_PATH = Path(__file__).absolute().parent
Hartmannsgruber
User
Beiträge: 89
Registriert: Mittwoch 15. Januar 2014, 22:30
Wohnort: Bad Kötzting
Kontaktdaten:

Wann werden dann globale Variablen verwendet?
Wie soll z.B. gehandhabt werden, wenn zwei verschiedene Klassen auf ein und die selbe Variable zugreifen?

Ich habe nach Betriebssystem unterschieden, da ja Linux und Windows einen unterschied mit den Strichen in
Pfadangaben machen ( "/", "\"). War mein Gedankengang hier zu kompliziert, oder habe ich dies falsch verstanden?
ich wollte einen absoluten Pfad zur Datei angeben.

Das mit den aufruf von .show() habe ich aus dem Buch von Herrn Weigend. Dieser ruft die Funktion in der __init__
Anweisung auf. Werde es aber umgehend umstellen.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Man verwendet nie globale Variablen. Wenn verschiedene Klassen oder Funktionen oder was auch immer Zugriff brauchen, werden die Variablen als Argumente übergeben.
Und für Pfade gibt es ja Path-Objekte, was Du ja auch benutzt hast, nur eben falsch.
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Hallo Hartmannsgruber ,
Wie soll z.B. gehandhabt werden, wenn zwei verschiedene Klassen auf ein und die selbe Variable zugreifen?
zum Beispiel so:

Code: Alles auswählen

class A(object):
    def __init__(self, variable):
        self.variable = variable        
        print("Klasse A, Methode init:", self.variable)
        self.start_klasse_b()            

    def start_klasse_b(self):
        b = B(self.variable)
        variable_aendern = b.variable_aendern()
        self.variable = b.variable_ausgebe()
        print("Klasse A, Methode start_klasse_b:", self.variable)

class B(object):
    def __init__(self, variable):
        self.variable = variable        
        self.variable_ausgebe()

    def variable_aendern(self):
        self.variable = "Veränderte Variable aus Klasse B"

    def variable_ausgebe(self):
        print("Klasse B, Methode variable_ausgebe:", self.variable)
        return self.variable

if __name__ == "__main__":
    start = A(variable = "Ursprüngliche Variable aus Klasse A")
Gruss
Peter
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@Peter: dass eine Methode die variable_ausgebe heißt, eine Variable zurückgibt ist sehr seltsam. Man würde auch direkt auf b.variable zugreifen.
`variable_aendern` liefert richtigerweise nichts zurück. Das Nichts an eine lokale Variable variable_aendern zu binden, macht keinen Sinn.
Antworten