it-swarm.com.de

Wie kann ich die Struktur (oder das Schema) eines Wörterbuchs in Python überprüfen?

Ich habe ein Wörterbuch mit Konfigurationsinformationen:

my_conf = {
    'version': 1,

    'info': {
        'conf_one': 2.5,
        'conf_two': 'foo',
        'conf_three': False,
        'optional_conf': 'bar'
    }
}

Ich möchte prüfen, ob das Wörterbuch der von mir benötigten Struktur folgt.

Ich suche so etwas:

conf_structure = {
    'version': int,

    'info': {
        'conf_one': float,
        'conf_two': str,
        'conf_three': bool
    }
}

is_ok = check_structure(conf_structure, my_conf)

Gibt es eine Lösung für dieses Problem oder eine Bibliothek, die die Implementierung von check_structure einfacher machen könnte?

14
Thyrst'

Ohne Bibliotheken zu verwenden, können Sie auch eine einfache rekursive Funktion wie folgt definieren:

def check_structure(struct, conf):
    if isinstance(struct, dict) and isinstance(conf, dict):
        # struct is a dict of types or other dicts
        return all(k in conf and check_structure(struct[k], conf[k]) for k in struct)
    if isinstance(struct, list) and isinstance(conf, list):
        # struct is list in the form [type or dict]
        return all(check_structure(struct[0], c) for c in conf)
    Elif isinstance(struct, type):
        # struct is the type of conf
        return isinstance(conf, struct)
    else:
        # struct is neither a dict, nor list, not type
        return False

Dies setzt voraus, dass die Konfiguration Schlüssel haben kann, die nicht in Ihrer Struktur enthalten sind, wie in Ihrem Beispiel.


Update: Neue Version unterstützt auch Listen, z. wie 'foo': [{'bar': int}] 

4
tobias_k

Sie können schema verwenden ( PyPi Link )

schema ist eine Bibliothek zum Validieren von Python-Datenstrukturen, z. B. aus Konfigurationsdateien, Formularen, externen Services oder Befehlszeilenanalyse, konvertiert von JSON/YAML (oder etwas anderem) in Python-Datentypen.

from schema import Schema, And, Use, Optional, SchemaError

def check(conf_schema, conf):
    try:
        conf_schema.validate(conf)
        return True
    except SchemaError:
        return False

conf_schema = Schema({
    'version': And(Use(int)),
    'info': {
        'conf_one': And(Use(float)),
        'conf_two': And(Use(str)),
        'conf_three': And(Use(bool)),
        Optional('optional_conf'): And(Use(str))
    }
})

conf = {
    'version': 1,
    'info': {
        'conf_one': 2.5,
        'conf_two': 'foo',
        'conf_three': False,
        'optional_conf': 'bar'
    }
}

print(check(conf_schema, conf))
24
Danil Speransky

@tobias_k schlug mich (sowohl in Bezug auf Zeit als auch Qualität wahrscheinlich), aber hier ist eine weitere rekursive Funktion für die Aufgabe, die für Sie (und mich) vielleicht etwas einfacher sein könnte:

def check_dict(my_dict, check_against):
    for k, v in check_against.items():
        if isinstance(v, dict):
            return check_dict(my_dict[k], v)
        else:
            if not isinstance(my_dict[k], v):
                return False
    return True
0
Ev. Kounis

Wörterbücher werden, wenn sie in Python verwendet und nicht als JSON exportiert werden, darin begründet, dass die Reihenfolge des Wörterbuchs nicht festgelegt werden muss. Beim Nachschlagen von Schlüsseln werden stattdessen Werte zurückgegeben (daher ein Wörterbuch).

In beiden Fällen sollten Sie mit diesen Funktionen wissen, nach was Sie nach dem Verschachtelungsgrad in den von Ihnen bereitgestellten Beispielen suchen.

#assuming identical order of keys is required

def check_structure(conf_structure,my_conf):
    if my_conf.keys() != conf_structure.keys():
        return False

    for key in my_conf.keys():
        if type(my_conf[key]) == dict:
            if my_conf[key].keys() != conf_structure[key].keys():
                return False

    return True

#assuming identical order of keys is not required

def check_structure(conf_structure,my_conf):
    if sorted(my_conf.keys()) != sorted(conf_structure.keys()):
        return False

    for key in my_conf.keys():
        if type(my_conf[key]) != dict:
            return False
        else:
            if sorted(my_conf[key].keys()) != sorted(conf_structure[key].keys()):
                return False

    return True

Diese Lösung müsste natürlich geändert werden, wenn der Verschachtelungsgrad größer wäre (d. H. Er ist so konfiguriert, dass er die Ähnlichkeit der Struktur von Wörterbüchern bewertet, die einige Werte als Wörterbücher haben, nicht jedoch Wörterbücher, bei denen einige dieser Wörterbücher auch Wörterbücher sind).

0
Will

Sie können Struktur mithilfe von Rekursion erstellen:

def get_type(value):
    if isinstance(value, dict):
        return {key: get_type(value[key]) for key in value}
    else:
        return str(type(value))

Vergleichen Sie dann die erforderliche Struktur mit Ihrem Wörterbuch:

get_type(current_conf) == get_type(required_conf)

Beispiel:

required_conf = {
    'version': 1,
    'info': {
        'conf_one': 2.5,
        'conf_two': 'foo',
        'conf_three': False,
        'optional_conf': 'bar'
    }
}

get_type(required_conf)

{'info': {'conf_two': "<type 'str'>", 'conf_one': "<type 'float'>", 'optional_conf': "<type 'str'>", 'conf_three': "<type 'bool'>"}, 'version': "<type 'int'>"}
0
Eugene Soldatov