configparser - schreiben von einem Wert in INI file

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
michpro
User
Beiträge: 19
Registriert: Samstag 27. Dezember 2014, 21:30

Hallo Forum,
ich habe aktuell ein Problem beim Schreiben von einem Wert in ein INI-File.

Aufbau des INI-File vor dem Schreiben:
[KuehlungWr]
SollTemp = 42
Hysterese = 2

Das Auslesen der Werte funktioniert ohne Probleme.
Möchte ich jedoch nur den Wert "SollTemp" ändern, so ist nach meiner Funktion "writeIniFile(iValue)" das Item Hysterese nicht mehr vorhanden.

Aufbau des INI-File nach dem Schreiben:
[KuehlungWr]
solltemp = 42



hier der entsprechende Code-Auszug:

Code: Alles auswählen

#Import für Qt
import sys
from PyQt5 import QtWidgets, QtCore, uic

#Import für Python
import datetime
import configparser


#lesen Werte aus INI File
def readIniFile(strItem):
    config=configparser.ConfigParser()
    config.sections()
    config.read('D:\Sandbox\TestPythonProjekte\KuehlungWechselrichter\KuehlungWechselrichter.ini')

    #Bestimmung Solltemperatur
    if (strItem == "SollTemp"):
        iRetVal = config['KuehlungWr']['SollTemp']

    #Bestimmung Schalthysterese
    if (strItem == "Hysterese"):
        iRetVal = config['KuehlungWr']['Hysterese']

    #Rückgabe
    print(str(iRetVal))
    return iRetVal


#schreiben Werte in INI File
def writeIniFile(iValue):
    config=configparser.ConfigParser()
    config['KuehlungWr'] = {}
    config['KuehlungWr']['SollTemp'] = str(iValue)

    with open('D:\Sandbox\TestPythonProjekte\KuehlungWechselrichter\KuehlungWechselrichter.ini', 'w') as configfile: config.write(configfile)


ich kann natürlich den Wert der Hysterese vor dem schreiben ebenfalls auslesen und dann wieder schreiben, kann mir aber nicht vorstellen, dass dies nich auch anderst geht.

Im Vorraus schon mal Danke!
michpro
BlackJack

@michpro: Die Funktionen sind ungünstig organisiert. Man würde normalerweise nicht für jeden Wert den man wissen möchte die Konfigurationsdatei neu laden, sondern einmal die Datei laden, die Konfiguration als Objekt behalten und nach dem Verändern dann wieder schreiben. INI-Dateien sind Textdateien, die muss man komplett laden und neu schreiben wenn man darin etwas ändern möchte.

Die Kommentare sind alle ziemlich nutzlos. Ein Kommentar sollte einen Mehrwert zum Code enthalten und nicht äusserst banale Sachen die man am Code sowieso schon ablesen kann noch mal wiederholen.

Diese komischen Typzusätze bei den Namen solltest Du bleiben lassen. Irgendwann stimmt der Zusatz nicht mehr, dann hast Du falsche, irreführende Namen, oder musst überall den Namen anpassen ohne das sich an der Bedeutung des Wertes etwas geändert hat. Dafür sind Namen ja da, dem Leser die Bedeutung zu vermitteln.

Der `config.sections()`-Aufruf in Zeile 13 macht keinen Sinn. Der bewirkt nichts.

Bei ``if`` braucht man keine Klammern um die Bedingung. Die Abfragen sind auch reichlich umständlich weil man das Argument der Funktion doch einfach direkt als Schlüssel für den Zugriff in den INI-Abschnitt verwenden kann.

Genau wie Code sollte man auch keine nicht-trivialen literale Werte wiederholen. Wenn Du den Namen oder Pfad der INI-Datei mal ändern möchtest, sollte das nicht mehrfach im ganzen Quelltext passieren müssen sondern nur an einer Stelle wo das als Konstante definiert wird.
michpro
User
Beiträge: 19
Registriert: Samstag 27. Dezember 2014, 21:30

ok,
habe das lesen mal versucht soweit wie möglich zusammenzukürzen...

Code: Alles auswählen

#Import für Python
import datetime
import configparser

INI_FILE = "D:\Sandbox\TestPythonProjekte\KuehlungWechselrichter\KuehlungWechselrichter.ini"

#lesen Werte aus INI File
def readIniFile(strItem):
    config=configparser.ConfigParser()
    config.read(INI_FILE)
    return config['KuehlungWr'][str(strItem)]
soweit so gut.
BlackJack hat geschrieben:Diese komischen Typzusätze bei den Namen solltest Du bleiben lassen
in erster Linie kann ich da besser erkennen was ich für einen Variablentyp habe... werde trotzdem mal versuchen darauf zu verzichten.

So, werde mich mal dran machen mir das INI File als Objekt zu holen, wobei ich bisher noch keinen Plan habe wie ich das bewerkstelligen soll, werde ich aber schon noch herausfinden.
BlackJack

@michpro: Die Typen sind ja nicht fest, zum Beispiel ist `iValue` bei der Funktion zum Schreiben im ersten Beitrag unnötig einschränkend denn da könnte man ja auch Werte mit anderen Typen übergeben. Zum Beispiel Zeichenketten. Zudem scheinst Du Deinen eigenen Namenszusätzen nicht zu trauen wenn Du ``str(strItem)`` schreibst.

Alles was man an einen Namen binden kann ist ein Objekt. Die eingelesene Konfigurationsdatei hast Du in Deiner Funktion ja zum Beispiel an den Namen `config` gebunden.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

michpro hat geschrieben:So, werde mich mal dran machen mir das INI File als Objekt zu holen,...
Hast Du doch schon, ``config`` ist das Objekt, mit dem Du arbeitest und am Ende wieder das ini-File zurückschreibst. Um Werte aus der config zu lesen, kannst Du Dir die Funktion doch sparen. Wie BlackJack schon sagte, behalte einfach die ``config``.

Code: Alles auswählen

def read_config(filename):
    config = configparser.ConfigParser()
    config.read(filename)
    return config

def write_config(filename, config):
    with open(filename, 'w') as configfile:
        config.write(configfile)

Code: Alles auswählen

config = read_config(INI_FILE)
# do
# some
# stuff
# with
# ``config``
write_config(INI_FILE, config)
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
michpro
User
Beiträge: 19
Registriert: Samstag 27. Dezember 2014, 21:30

ok,
ich glaub ich hab es kapiert. Wenn ich am Anfang meiner Klasse "MainViev" die INI-Datei lese und ihr dann den "Objektnamen" config zuweise, kann über die komplette Laufzeit hier Werte zuweisen und abfragen?
z.B. so:

Code: Alles auswählen

class MainView(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainView, self).__init__()
        uic.loadUi("MainView.ui", self)

        config = readConfig(INI_FILE)
        ...
        ...
        self.pB_SollTempUeber.clicked.connect(self.SollTempUebernahme)
        ...
        ...
    #Funktion Solltemperatur übernehmen
    def SollTempUebernahme(self):
        iValue=self.SliderSollTemp.value()
        print(str(iValue))
        config['KuehlungWr']['SollTemp'] = str(iValue)
        writeConfig(INI_FILE, config)
vielen Dank an Euch
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

michpro hat geschrieben:... z.B. so:
Nein, so nicht. Attribute, die innerhalb einer Klasseninstanz verfügbar sein sollen, musst Du auch an die Instanz binden. In diesem Fall ist ``config`` innerhalb der ``__init__`` Methode ein anderes als innerhalb der ``SollTempUebernahme`` Methode. Und woher kommen ``readConfig``, ``writeConfig`` und ``INI_FILE``?

Die Schreibweise Deiner Methodennamen ist nicht pythonlike. Methoden-/Funktionsnamen werden klein geschrieben und einzelne Wörter durch Unterstrich getrennt.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
michpro
User
Beiträge: 19
Registriert: Samstag 27. Dezember 2014, 21:30

hmmm... nun gut wenn ich mein Beispiel folgender massen umbau funktioniert es.

Code: Alles auswählen

# -*- coding: utf-8 -*-
#Import für Qt
import sys
from PyQt5 import QtWidgets, QtCore, uic

#Import für Python
import datetime
import configparser


#Konstanten
INI_FILE = "D:\Sandbox\TestPythonProjekte\KuehlungWechselrichter\KuehlungWechselrichter.ini"


#INI File: lesen
def read_config(filename):
    config = configparser.ConfigParser()
    config.read(filename)
    return config
 
#INI File: schreiben
def write_config(filename, config):
    with open(filename, 'w') as configfile:
        config.write(configfile)

class MainView(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainView, self).__init__()
        uic.loadUi("MainView.ui", self)
        config = read_config(INI_FILE)
        self.pB_SollTempUeber.clicked.connect(self.soll_temp_uebernahme)
        #MainView anzeigen
        self.show()

    #Funktion Solltemperatur übernehmen
    def soll_temp_uebernahme(self):
        config = read_config(INI_FILE)
        iValue=self.SliderSollTemp.value()
        print(str(iValue))
        config['KuehlungWr']['SollTemp'] = str(iValue)
        write_config(INI_FILE, config)
 

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MainView()
    sys.exit(app.exec_())
Nur so öffne ich hier mein "Objekt" das INI-File in der Funktion soll_temp_uebernahme, bei einer weiteren Funktion wie hysterese_uebernahme muss ich dann dort ebenfalls das Objekt wieder öffnen.
Weiter dachte ich die Funktion soll_temp_uebernahme ist hier mit "self"bereits in der Klasse MainView eingebunden. Der Funktionsaufruf funktioniert auch tadellos.
BlackJack

@michpro: Warum lädst Du die Konfiguration in der `__init__()`-Methode und tust dann nichts damit?
michpro
User
Beiträge: 19
Registriert: Samstag 27. Dezember 2014, 21:30

Da bin ich wohl einem Denkfehler aufgesessen. Ich wollte das INI-FIle nur einmalig laden und in mehreren Funktionen beschreiben.

Ich habe mein Problem jetzt ja doch gelöst bekommen. Muss mir glaub die Doku zu Instanzen,Methoden,Attribute nochmals zu Gemüte ziehen.

trotzdem Danke an Euch!

michpro
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@michpro
Eigentlich hat das ganze Konfigurationszeugs nichts in der ``MainView`` zu suchen. Alles, das mit Datenverwaltung zusammenhängt von allem, das mit der Anzeige zu tun hat zu trennen, ist ein gutes und wichtiges Prinzip beim Programmieren.
Ich würde also eine ``Config`` Klasse machen, dessen Instanz Du dann durch alle anderen Bereiche schicken kannst. Sowas in der Art:

Code: Alles auswählen

class Config(object):
    def __init__(self, configfile):
        self.configfile = configfile
        self.config = self.read()

    def read(self):
        config = configparser.ConfigParser()
        config.read(self.configfile)
        return config

    def write(self):
        with open(self.configfile, 'w') as configfile:
            self.config.write(configfile)

    def add(self, section, option, value):
        pass

    def remove(self, section, value):
        pass

    def ask(self, section, value):
        pass


if __name__ == '__main__':
    app = QtWidgets.QApplications(sys.argv)
    config = Config(INI_FILE)
    window = MainView(config)
    sys.exit(app.exec_())
Dadurch kannst Du alles, das mit Konfigurationsdaten zu tun hat (und das wird mit der Zeit nicht wenig sein...), in einem eigenen Bereich verwalten.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
michpro
User
Beiträge: 19
Registriert: Samstag 27. Dezember 2014, 21:30

So, jetzt bin ich es nochmals. Habe mal versucht eure Ratschläge umzusetzen.
Ich habe für mein kleines Programm die Klasse "Config" angelegt um dort alles was mit INI-Files lesen/schreiben zu tun hat abzuhandeln. Dann habe ich die Klasse "Filehandling" angelegt um dort alles was mit Log-Files lesen/schreiben zu tun hat abzuhandeln. Die Klasse "MainView" zur Visualisierung und Einstellung bleibt bestehen. Von ihr rufe ich dann die Klassen "Config" und "Filehandling" auf.
Werte welche immer gleich bleiben und mehrmals benützt werden habe ich als Konstanten deklariert.
@BlackJack von den Typzusätzen von den Variablen bin ich noch nicht ganz losgekommen, auch wenn du mir geraten hast dies zu tun. Habe zwar versucht diese zu eleminieren, aber teilweise fällt es mir doch leichter wenn ich z.B. bei Integer Variable ein i vorstelle.
Die Namensgebung der Funktionen habe ich nach Python-Style abgeändert.
Folgender Code läuft so wie ich es mir vorstelle. Ich würde euch bitten nochmals kurz drüber zu sehen ob der soweit in Ordnung ist.
Ach ja, eine Frage habe ich dann doch noch. In der Funktion "read_log_soll_temp" öffne ich ein TXT-File und schliesse es nicht mehr expizit. Ist das so iO. oder sollte ich da am Ende doch noch lieber ein fobj_read.close() schreiben?

Code: Alles auswählen

# -*- coding: utf-8 -*-


#Import für Qt
import sys
from PyQt5 import QtWidgets, QtCore, uic

#Import für Python
import datetime
import configparser

#Konstanten
INI_FILE = "D:\Sandbox\TestPythonProjekte\KuehlungWechselrichter\KuehlungWechselrichter.ini"
LOG_FILE_SOLL_TEMP = "D:\Sandbox\TestPythonProjekte\KuehlungWechselrichter\LogTempSoll.txt"
LOG_FILE_HYSTERESE = "D:\Sandbox\TestPythonProjekte\KuehlungWechselrichter\LogHysterese.txt"
INI_SEKTION_KUEHLUNG_WR = "KuehlungWr"
INI_ITEM_SOLL_TEMP = "SollTemp"
INI_ITEM_HYSTERESE = "Hysterese"



#Klasse Config anlegen
class Config(object):
    def __init__(self, configfile):
        self.configfile = configfile
        self.config = self.read()
 

    #INI File: lesen
    def read(self):
        config = configparser.ConfigParser()
        config.read(self.configfile)
        return config
    

    #INI File: schreiben
    def write(self):
        with open(self.configfile, 'w') as configfile:
            self.config.write(configfile)
 

    #INI File: einen Wert ermitteln
    def read_value_ini_file(self, Item):
        self.read()
        return self.config[INI_SEKTION_KUEHLUNG_WR][str(Item)]


    #INI File: einen Wert schreiben
    def write_value_ini_file(self, Item, iValue):
        self.read()

        #Festlegung Solltemperatur
        if (str(Item) == INI_ITEM_SOLL_TEMP):
            self.config[INI_SEKTION_KUEHLUNG_WR][INI_ITEM_SOLL_TEMP] = str(iValue)

        #Festlegung Schalthysterese
        if (str(Item) == INI_ITEM_HYSTERESE):
            self.config[INI_SEKTION_KUEHLUNG_WR][INI_ITEM_HYSTERESE] = str(iValue)

        self.write()



#Klasse Filehandling anlegen
class Filehandling(object):
    def __init__(self):
        super(Filehandling, self).__init__()

    #letzte Änderung der Solltemperaur aus Log File ermitteln
    def read_log_soll_temp(self):
        #Datei öffnen und lesen
        fobj_read = open(LOG_FILE_SOLL_TEMP, 'r').readlines()
        i=0                                     # Laufvariable initalisieren
        for line in fobj_read:
            i = i+1
        lastValue = fobj_read[i-1]              # letzter Eintrag in Log File
        Laenge_lastValue = len(lastValue)       # String Länge bestimmen
        strRetVal = lastValue[0:Laenge_lastValue-5]
        return strRetVal



    #letzte Änderung der Hysterese aus Log File ermitteln
    def read_log_hysterese(self):
        #Datei öffnen und lesen
        fobj_read = open(LOG_FILE_HYSTERESE, 'r').readlines()
        i=0                                     # Laufvariable initalisieren
        for line in fobj_read:
            i = i+1
        lastValue = fobj_read[i-1]              # letzter Eintrag in Log File
        Laenge_lastValue = len(lastValue)       # String Länge bestimmen
        strRetVal = lastValue[0:Laenge_lastValue-5]
        return strRetVal



    #Änderung der Solltemperatur mit Zeitstempel in Log File speichern
    def write_log_soll_temp(self, SollTemp):
        #Zeitstempel generieren
        strZeitstempel = datetime.datetime.now().strftime("%Y.%m.%d %H:%M:%S")
        print (strZeitstempel + " ; " + str(SollTemp)) #Ausgabe im Python Shell
        #Datei öffnen und übernommene Solltemperatur schreiben
        fobj_write = open(LOG_FILE_SOLL_TEMP,"a")
        fobj_write.write(strZeitstempel + " ; " + str(SollTemp) +"\n")
        fobj_write.close()



    #Änderung der Hysterese mit Zeitstempel in Log File speichern
    def write_log_hysterese(self, Hysterese):
        #Zeitstempel generieren
        strZeitstempel = datetime.datetime.now().strftime("%Y.%m.%d %H:%M:%S")
        print (strZeitstempel + " ; " + str(Hysterese)) #Ausgabe im Python Shell
        #Datei öffnen und übernommene Hysterese schreiben
        fobj_write = open(LOG_FILE_HYSTERESE,"a")
        fobj_write.write(strZeitstempel + " ; " + str(Hysterese) +"\n")
        fobj_write.close()



#Klasse MainView anlegen
class MainView(QtWidgets.QMainWindow):
    def __init__(self, config, filehandling):
        super(MainView, self).__init__()
        uic.loadUi("MainView.ui", self)

        #Solltemperatur lesen / Schieberegler und LCD Anzeige initalisieren
        iAktValue = config.read_value_ini_file(INI_ITEM_SOLL_TEMP)
        self.SliderSollTemp.setValue(int(iAktValue))
        self.LcdSollTemp.display(int(iAktValue))

        #Schalthysteres lesen / Schieberegler und LCD Anzeige initalisieren
        iAktValue = config.read_value_ini_file(INI_ITEM_HYSTERESE)
        self.SliderHysterese.setValue(int(iAktValue))
        self.LcdHysterese.display(int(iAktValue))

        #letzte Änderung der Solltemperatur ermitteln
        self.lb_change_solltemp_akt()

        #letzte Änderung der Hysterese ermitteln
        self.lb_change_hysterese_akt()

        #Initalisieren Signal / Slots
        self.SliderSollTemp.valueChanged.connect(self.soll_temp_aenderung)
        self.SliderHysterese.valueChanged.connect(self.hysterese_aenderung)
        self.pB_SollTempUeber.clicked.connect(self.soll_temp_uebernahme)
        self.pB_HystereseUeber.clicked.connect(self.hysterese_uebernahme)

        #Schalttemperaturen für Lüfter berechnen
        self.berechnung_schalttemp_luefter()

        #MainView anzeigen
        self.show()

    #Funktion Label für letzte Änderung der Soll Temperatur richtigstellen
    def lb_change_solltemp_akt(self):
        strLastChange = filehandling.read_log_soll_temp()
        self.lbLetztAenderungValue.setText(strLastChange)

    #Funktion Label für letzte Änderung der Hysterese richtigstellen
    def lb_change_hysterese_akt(self):
        strLastChange = filehandling.read_log_hysterese()
        self.lbLetztAenderungValueHysterese.setText(strLastChange)

    #Funktion Änderung Solltemperatur
    def soll_temp_aenderung(self):
        Value=self.SliderSollTemp.value()
        self.LcdSollTemp.display(Value)

    #Funktion Änderung Hysterese
    def hysterese_aenderung(self):
        Value=self.SliderHysterese.value()
        self.LcdHysterese.display(Value)

    #Funktion Solltemperatur übernehmen
    def soll_temp_uebernahme(self):
        iValue=self.SliderSollTemp.value()
        print(str(iValue))
        config.write_value_ini_file(INI_ITEM_SOLL_TEMP, iValue)
        filehandling.write_log_soll_temp(iValue)
        self.lb_change_solltemp_akt()

    #Funktion Solltemperatur übernehmen
    def hysterese_uebernahme(self):
        iValue=self.SliderHysterese.value()
        print(str(iValue))
        config.write_value_ini_file(INI_ITEM_HYSTERESE, iValue)
        filehandling.write_log_hysterese(iValue)
        self.lb_change_hysterese_akt()

    def berechnung_schalttemp_luefter(self):
        print("SchalttempLüfter")

    
if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    config = Config(INI_FILE)
    filehandling = Filehandling()
    window = MainView(config, filehandling)
    sys.exit(app.exec_())
nochmals ein Danke an alle für Eure Geduld und Hilfe
michpro
BlackJack

@michpro: Da macht einiges überhaupt keinen Sinn. Zum Beispiel die Klasse `Filehandling`. Warum ist das eine Klasse? Das wird überhaupt nicht verwendet das man da ein Objekt mit einem Zustand hat, beziehunsgweise haben die Objekt davon überhaupt gar keinen Zustand. Das sind einfach nur vier Funktionen die ohne Sinn in einer Klasse gesteckt wurden. Das heisst eigentlich sind das nur zwei Funktionen, denn die beiden `read_*()`- beziehunsgweise `write_*()`-Funktionen sind jeweils so verdammt ähnlich dass das sicher keine eigenen Funktionen sein sollten.

Die Lesefunktionen sind pervers umständlich. Es werden erst alle Zeilen in den Speicher gelesen in eine Liste. Dann gehst Du die Liste in einer Schleife durch um dabei manuell einen Zähler hochzusetzen um die den Index der letzten Zeile zu bestimmen. Ernsthaft? Listen haben eine Länge die man mit `len()` abfragen kann. Ohne durch alle Elemente zu iterieren. Aber nicht einmal das bräuchte man, denn jedes Anfängertutorial sollte bei Listen eigentlich auch erwähnen das negative Indexzugriffe ”von hinten” zählen. Also ein ``a_list[-1]`` das letzte Element einer Liste liefert. Aber wenn man nicht alle Zeilen in einer Liste einliest, obwohl man nur die letzte Zeile haben möchte, dann kann man einfach eine ``for``-Schleife über die Datei ausführen. Die Laufvariable ist dann am Ende an die Zeile aus dem letzten Schleifendurchlauf gebunden, also an die letzte Zeile aus der Datei. Sofern überhaupt Zeilen in der Datei vorhanden sind. Diesen Sonderfall behandelt Dein Code nicht. Warum von der leztzen Zeile alles ausser den letzten 5 Zeichen als Rückgabewert genommen wird ist mir ein Rätsel. Das soll doch hoffentlich nicht bedeuten das Du *hoffst* damit den Wert abzuschneiden weil der *vielleicht* immer vier Zeichen lang ist + das Zeilenendezeichen? Das ist extrem fehleranfällig.

Der Name `fobj_read` für eine Liste mit Zeilen ist so gar nicht offensichtlich. Das könnte man zum Beispiel `lines` nennen.

Dateien sollte man wenn möglich zusammen mit der ``with``-Anweisung öffnen und damit das schliessen der Datei unter allen Umständen sicher zu stellen.

Für CSV-Dateien gibt es in der Standardbibliothek ein Modul: `csv`.

Die Kommentare sind fast alle überflüssig. Kommentare sollen dem Leser Zusatzinformationen vermitteln die aus dem Code nicht ersichtlich werden und nicht noch mal das offensichtliche wiederholen was sowieso schon deutlich im Code da steht. Faustregel: Nicht kommentieren *was* gemacht wird, das steht da ja schon als Code, sondern *warum* — aber nur sofern das nicht auch aus dem Code schon ersichtlich ist.

Das `filehandling`-Argument der `MainView.__init__()` wird nirgends verwendet, dafür greifen Methoden der Klasse auf das modulglobale `filehandling`-Objekt zu, was sie nicht tun sollten. Der Name sollte auf Modulebene gar nicht definiert sein. Das Hauptprogramm gehört in eine Funktion damit so etwas nicht passieren kann.

Die Methoden für die Slideränderungen sind überflüssig, da hätte man das `valueChanged()`-Ereignis direkt mit der `display()`-Methode von den LCD-Widgets verbinden können.

`configfile` wäre ein guter Name für ein Dateiobjekt, aber nicht für einen Datei*namen*.

Die `self.read()`-Aufrufe in der `Config`-Klasse ausserhalb der `__init__()` sind sinnfrei weil die keinen Effekt haben. Die `read()`-Methode sollte das Konfigurationsobjekt nicht zurückgeben sondern den internen Zustand des `Config`-Objekts setzen.

Die `write_value_ini_file()`-Methode enthält ja wieder diese komisch unsinnig-umständlichen ``if``\s und sinnfreie `str()`-Aufrufe und Klammern um die ``if``-Bedingungen.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

BlackJack hat geschrieben:Die `read()`-Methode sollte das Konfigurationsobjekt nicht zurückgeben sondern den internen Zustand des `Config`-Objekts setzen.
Das hat michpro so von mir übernommen. Und ich hab' das so gemacht, weil ich Klassenattribute immer gerne in der ``__init__`` und nicht in irgendeiner Methode setze. Ok, die ``read`` und ``write`` Methoden könnte man ``_read`` und ``_write`` nennen, damit klar ist, dass beide eigentlich nur innerhalb der Klasse verwendet werden sollten. Wie würdest Du das anderst machen?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Statt

Code: Alles auswählen

def read(self):
        config = configparser.ConfigParser()
        config.read(self.configfile)
        return config
einfach

Code: Alles auswählen

def read(self):
        self.config = configparser.ConfigParser()
        self.config.read(self.configfile)
.

Es handelt sich bei config übrigens um ein Attribut und nicht um ein Klassenattribut.
Das Leben ist wie ein Tennisball.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

EyDu hat geschrieben:Statt [...] einfach [...]
Ja, das ist schon klar, meine Frage war jetzt eher, ob es nicht grundsätzlich besserer Stil ist, Attribute (Klassenattribut ist falsch :oops: , danke für den Hinweis!) wenn möglich innerhalb von ``__init__`` zu setzen...?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Da würde ich das auch setzten. In diesem Fall wohl auf `None` und dann die `read()`-Methode aufrufen die es auf den richtigen Wert setzt.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ah, ok. Dann habe ich die Intention deiner Frage falsch verstanden. Ich entscheide das immer von Fall zu Fall. Ich tendiere auch eher dazu den Rückgabewert in der __init__-Methode an ein Attribut zu binden, da ich so eine Übersicht über alle verwendeten Attribute habe. Wenn eine Methode allerdings viel auf Attributen des Objekts rumarbeitet und es sinnvoll mehrere Attribute in einem Rutsch erstellt werden, dann verzichte ich auch auf eine explizite Zuweisung. Dafür spendiere ich der __init__-Methode dann Zeilen der Art

Code: Alles auswählen

self.attribute1 = None
self.attribute2 = None
und rufe dann die Methode zur Initialisierung auf.

Wichtig ist eher, dass alle Attribute nach dem Durchlauf der __init__-Methode erzeugt wurden und nicht erst irgendwann beim Aufruf einer anderen Methode angelegt werden.
Das Leben ist wie ein Tennisball.
Antworten