2017-08-22 53 views
6

我有配置信息的字典:如何在Python中驗證字典的結構(或模式)?

my_conf = { 
    'version': 1, 

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

我要檢查如果字典遵循我所需要的結構。

我正在尋找這樣的事情:

conf_structure = { 
    'version': int, 

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

is_ok = check_structure(conf_structure, my_conf) 

是否有或做這個問題的任何解決方案,可以使執行check_structure更容易的任何圖書館嗎?

回答

3

不使用庫,你也可以定義一個簡單的遞歸函數如下:

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) 
    else: 
     # struct is the type of conf 
     return isinstance(conf, struct) 

這是假設的配置可以不在你的結構密鑰,如你的榜樣。

8

您可以使用schemaPyPi Link

模式是用於驗證Python數據結構,例如從配置-文件,表格,外部服務或命令行解析獲得的那些文庫,從轉換JSON/YAML(或其他)到Python數據類型。

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)) 
+0

看起來不錯!謝謝:) –

+0

這是從文檔複製粘貼。這將如何幫助OP?你能提供一個具體的例子顯示如何?這並不比僅有鏈接的答案好得多。 –

+0

@cᴏʟᴅsᴘᴇᴇᴅ因爲它演示了OP可能需要的所有功能,並展示瞭如何在高級條件下使用lambdas。但你是對的,我會給我的答案添加一個具體的例子。 –

0

@tobias_k打我給它(無論是在時間和質量可能),但這裏是任務的另一遞歸函數可能會更容易一點你(和我)遵循:

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

你可以使用遞歸構建結構:

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

,然後比較所需的結構,你的字典裏:

get_type(current_conf) == get_type(required_conf) 

實施例:

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

字典的性質,如果在python正在使用它們,而不是導出爲一些JSON,是字典的順序不必設置。相反,查找鍵返回值(因此是字典)。

在任何一種情況下,這些函數都會爲您提供您所尋找的您提供的樣本中的嵌套級別。

#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 

這個解決方案顯然需要如果嵌套的水平的情況下(被改變即,它被配置成評估在具有一些值作爲字典的字典的結構的相似性,但不字典其中一些值,這些後者字典也是字典)。