HiveNetCore.utils.value_tool 源代码
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# Copyright 2018 黎慧剑
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
值处理通用工具
@module value_tool
@file value_tool.py
"""
__MOUDLE__ = 'value_tool' # 模块名
__DESCRIPT__ = u'值处理通用工具' # 模块描述
__VERSION__ = '0.1.0' # 版本
__AUTHOR__ = u'黎慧剑' # 作者
__PUBLISH__ = '2018.09.30' # 发布日期
from ruamel.yaml.comments import CommentedSeq
[文档]class ValueTool(object):
"""
值处理通用工具
"""
[文档] @classmethod
def get_dict_value(cls, key, dict_obj, default_value=None):
"""
获取字典指定值
@param {object} key - 字典key值
@param {dict} dict_obj - 要查的字典
@param {object} default_value=None - 如果取不到的默认值
@returns {object} - 去到值
"""
_value = default_value
if key in dict_obj.keys():
_value = dict_obj[key]
return _value
[文档] @classmethod
def set_dict_nest_value(cls, dict_obj, *args):
"""
按嵌套方式设置字典的值
@param {dict} dict_obj - 要设置的字典
@param {*args} - 除最后一个参数都为str格式的字典key值,最后一个参数为要设置的值
注: 最后形成的格式类似为 {
args[0]: {args[1]: {args[2]: {args[3]: 值}}}
}
@return {dict} - 返回当前字典对象
"""
_len = len(args)
if _len < 2:
# 没有具体设置值,不处理
return dict_obj
# 遍历进行处理
_dict = dict_obj
_i = 0
while _i < _len - 2:
_dict.setdefault(args[_i], {})
_dict = _dict[args[_i]]
_i += 1
# 最后一个为值
_dict[args[_i]] = args[_i + 1]
return dict_obj
[文档] @classmethod
def get_sorted_list_by_key(cls, dict_obj: dict, reverse=False):
"""
获取按key值排序后的key列表清单
@param {dict} dict_obj - 要处理的字典
@param {bool} reverse=False - 排序规则,reverse = True 降序 , reverse = False 升序(默认)
@return {list} - 按key值排序后的key列表
"""
return sorted(dict_obj, reverse=reverse)
[文档] @classmethod
def get_sorted_list_by_value(cls, dict_obj: dict, reverse=False):
"""
获取按value值排序后的字典对象清单
@param {dict} dict_obj - 要处理的字典
@param {bool} reverse=False - 排序规则,reverse = True 降序 , reverse = False 升序(默认)
@return {list} - 按key值排序后的对象清单[(key, value), (key, value), ...]
"""
return sorted(dict_obj.items(), key=lambda kv: (kv[1], kv[0]), reverse=reverse)
[文档] @classmethod
def merge_dict(cls, base_dict: dict, *args) -> dict:
"""
嵌套合并字典
@param {dict} base_dict - 基础字典, 所有字典都在该字典基础上进行合并
注: 将直接在该字典对象上修改
@param {*args} - 每一个参数为要合并的一个字典对象
@returns {dict} - 合并后的字典
"""
for _dict in args:
for _key, _val in _dict.items():
# 逐个key进行合并处理
if _key not in base_dict.keys() or not isinstance(base_dict[_key], dict) or not isinstance(_val, dict):
# 非字典形式, 直接覆盖即可
base_dict[_key] = _val
continue
# 字典形式, 使用自身处理下一级
base_dict[_key] = cls.merge_dict(base_dict[_key], _val)
return base_dict
[文档] @classmethod
def get_dict_value_by_path(cls, path: str, dict_obj: dict, default_value=None):
"""
获取字典指定路径的值
@param {str} path - 检索路径
注1: 从根目录开始搜索, 路径下多个key之间使用'/'分隔, 例如 'root/key1/key2'
注2: 可以通过[索引值]搜索特定key下第几个配置(数组或字典), 例如 'root/key1[0]'搜素key1下第一个对象
@param {dict} dict_obj - 字典对象
@param {Any} default_value=None - 如果搜索不到返回的默认值
"""
_last_obj = dict_obj
_paths = path.split('/')
_path_max_index = len(_paths) - 1 # 最后一个路径索引
try:
for _index in range(_path_max_index + 1):
# 获取路径中的完整信息
_key_paths = _paths[_index].split('[')
_key = _key_paths[0] # 要搜索的key
_sub_idxs = [] # key下对象的第几个
for _sub_idx in range(1, len(_key_paths)):
_sub_idxs.append(int(_key_paths[_sub_idx][0: -1]))
_sub_idxs_len = len(_sub_idxs)
_last_obj = _last_obj[_key]
for _idx in range(_sub_idxs_len):
if type(_last_obj) in (CommentedSeq, list):
# 按顺序获取指定位置的数组值
_last_obj = _last_obj[_sub_idxs[_idx]]
else:
# 按字典顺序位置获取指定位置的字典
_sub_key = list(_last_obj.keys())[_sub_idxs[_idx]]
_last_obj = _last_obj[_sub_key]
if _index == _path_max_index:
# 已经是最后一级, 返回对象的值即可
return _last_obj
except:
# 获取异常, 返回默认值
return default_value
[文档] @classmethod
def set_dict_value_by_path(cls, path: str, dict_obj: dict, set_value, auto_create_key: bool = False):
"""
设置字典指定路径的值
@param {str} path - 检索路径
注1: 从根目录开始搜索, 路径下多个key之间使用'/'分隔, 例如 'root/key1/key2'
注2: 可以通过[索引值]搜索特定key下第几个配置(数组或字典), 例如 'root/key1[0]'搜素key1下第一个对象
@param {dict} dict_obj - 字典对象
@param {Any} set_value - 要设置的值
@param {bool} auto_create_key=False - 是否自动创建不存在的Key
注: 自动创建的对象固定为dict
"""
_last_obj = dict_obj
_paths = path.split('/')
_path_max_index = len(_paths) - 1 # 最后一个路径索引
for _index in range(_path_max_index + 1):
# 获取路径中的完整信息
_key_paths = _paths[_index].split('[')
_key = _key_paths[0] # 要搜索的key
_sub_idxs = [] # key下对象的第几个
for _sub_idx in range(1, len(_key_paths)):
_sub_idxs.append(int(_key_paths[_sub_idx][0: -1]))
_sub_idxs_len = len(_sub_idxs)
_max_sub_idx = _sub_idxs_len - 1
if _sub_idxs_len == 0:
# 没有位置索引的情况
if _index == _path_max_index:
# 最后一级设置
_last_obj[_key] = set_value
return
# 要继续往下搜索
if auto_create_key and _key not in _last_obj.keys():
# 自动创建不存在的key
_last_obj[_key] = dict()
_last_obj = _last_obj[_key]
# 没有位置索引, 继续下一个搜索循环
continue
# 有位置索引的情况
if auto_create_key and _key not in _last_obj.keys():
# 自动创建不存在的key
_last_obj[_key] = dict()
_last_obj = _last_obj[_key]
# 逐级处理
for _idx in range(_sub_idxs_len):
if type(_last_obj) in (CommentedSeq, list):
if _idx == _max_sub_idx and _index == _path_max_index:
# 最后一级设置
_last_obj[_sub_idxs[_idx]] = set_value
return
else:
_last_obj = _last_obj[_sub_idxs[_idx]]
else:
# 字典情况
_sub_key = list(_last_obj.keys())[_sub_idxs[_idx]]
if _idx == _max_sub_idx and _index == _path_max_index:
_last_obj[_sub_key] = set_value
return
else:
_last_obj = _last_obj[_sub_key]
if __name__ == '__main__':
# 当程序自己独立运行时执行的操作
# 打印版本信息
print(('模块名: %s - %s\n'
'作者: %s\n'
'发布日期: %s\n'
'版本: %s' % (__MOUDLE__, __DESCRIPT__, __AUTHOR__, __PUBLISH__, __VERSION__)))