Seite 2 von 2

Re: INI-Datei einlesen, trotz fehlenden Sektionen/Optionen

Verfasst: Sonntag 24. April 2016, 14:15
von bwbg
Ich habe nochmals über die Problematik des Zusammenfassens der Konfigurationen nachgedacht und herausgekommen ist folgendes Programm. Dieses sollte nun soweit funktionieren, wie in meiner ersten Antwort aufgezeichnet. Darüber hinaus verwendet die get_configuration-Funktion nunmehr einen Dateiobjekt, so spielt es besser mit Sirius3s Beispiel zusammen:

Code: Alles auswählen

#!/usr/bin/env python3
import configparser
import itertools


def get_configuration(file_object):  # -> dict
    parser = configparser.ConfigParser()
    parser.read_file(file_object)
    return {section: dict(parser.items(section))
            for section
            in parser.sections()}

            
def merge_dicts(a, b):  # -> dict
    """Merges two dicts prefering the values of the second one."""
    return {k: v for k, v in itertools.chain(a.items(), b.items())}

    
def merge_configurations(a, b):  # -> dict
    # 1. Dafür Sorge trage, dass das Ergebnis die Sektionen beider
    #    Konfigurationen enthält. Hierzu bilde ich zunächst ein set
    #    (=Menge) über die Sektionsnamen beider Konfigurationen.
    section_names = set(itertools.chain(a.keys(), b.keys()))
    
    # 2. Dictionary erzeugen und die Inhalte der Sektionen
    #    zusammenfassen (merge_dicts). Hierbei werden die Inhalte des
    #    zweiten Konfiguration bevorzugt.
    return {section_name: merge_dicts(a.get(section_name, {}),
                                      b.get(section_name, {}))
            for section_name
            in section_names}
    

def main():
    with open('default.ini') as default_config_file:
        default_configuration = get_configuration(default_config_file)
        
    with open('user.ini') as user_config_file:
        user_configuration = get_configuration(user_config_file)
        
    print(merge_configurations(default_configuration, user_configuration))

    
if __name__ == '__main__':
    main()
Hier bietet sich ein Blick in die Dokumentation zu itertools und zu LC/DC im Allgemeinen an.

PS: Ich nutze ausschließlich Python 3.5., configparser.ConfigParser.read_file im obigen Beispiel müsste ggf. durch readfp ersetzt werden. readfp ist ab Python 3.2 veraltet.

Re: INI-Datei einlesen, trotz fehlenden Sektionen/Optionen

Verfasst: Sonntag 24. April 2016, 14:48
von BlackJack
@bwbg: Die „dict comprehension“ finde ich hier ungünstig. Wenn man mit den Schlüssel/Wert-Paaren nichts macht, kann man auch einfacher und kürzer einfach `dict()` verwenden: ``return dict(itertools.chain(a.items(), b.items()))``. Alternativ ginge auch noch ``result = dict(a); result.update(b); return result``.

Re: INI-Datei einlesen, trotz fehlenden Sektionen/Optionen

Verfasst: Sonntag 24. April 2016, 14:55
von bwbg
Für die Funktion merge_dicts stimme ich Dir sogar zu ... 8)

Re: INI-Datei einlesen, trotz fehlenden Sektionen/Optionen

Verfasst: Sonntag 24. April 2016, 14:56
von Sirius3
die einzeilige Variante wäre `result = dict(a, **b)`.

Re: INI-Datei einlesen, trotz fehlenden Sektionen/Optionen

Verfasst: Sonntag 24. April 2016, 15:04
von Sophus
@Sirius3: Damit ich hinterher komme, bedeuten diese beiden Sternchen (**), dass das Wörterbuch in einem Rutsch aktualisiert wird? Denn ich kenne diese Sternchen nur im Kontext von Funktionen (*args, **kwargs), um beliebe Anzahl von Argumenten oder Positionensargumente übergeben zu können.

Re: INI-Datei einlesen, trotz fehlenden Sektionen/Optionen

Verfasst: Sonntag 24. April 2016, 15:08
von BlackJack
@Sophus: Die ``**`` bedeuten hier genau das gleiche wie bei jedem anderen Funktions- oder Methodenaufruf.

Re: INI-Datei einlesen, trotz fehlenden Sektionen/Optionen

Verfasst: Sonntag 24. April 2016, 15:09
von bwbg
Sirius3 hat geschrieben:die einzeilige Variante wäre `result = dict(a, **b)`.
Das Problem hier ist jedoch, dass eine (unvollständige) Sektion aus der user.ini die entsprechende aus der default.ini ersetzt. merge_configurations ließe sich in einem Ausdruck schreiben, aber nicht wirklich lesbar in einer Zeile :wink:

Sophus hat nun vom Baum der Erkenntnis gekostet: Jede neue Antwort bringt neue Fragen.

Re: INI-Datei einlesen, trotz fehlenden Sektionen/Optionen

Verfasst: Sonntag 24. April 2016, 18:35
von DasIch
Sirius3 hat geschrieben:die einzeilige Variante wäre `result = dict(a, **b)`.
Hm.

Code: Alles auswählen

>>> a = {1: 2}
>>> b = {1: 3, 2: 3}
>>> c = {2: 4, 3: 4}
>>> dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
>>> {**a, **b}
{1: 3, 2: 3}
>>> {**a, **b, **c}
{1: 3, 2: 4, 3: 4}
Die tolle neue Syntax gibt es übrigens seit 3.5 und ist in PEP 448 beschrieben.

Re: INI-Datei einlesen, trotz fehlenden Sektionen/Optionen

Verfasst: Sonntag 24. April 2016, 18:59
von BlackJack
@DasIch: Bei der Konfiguration kann man allerdings davon ausgehen, dass die Schlüssel Zeichenketten sind. :-)