TLDR:我想让一个函数运行某些异常,最后显示它们并使函数引发异常。
我正在构建一个函数(见下文),通过创建表格" value":" path"来获取字典中每个值的路径。我有一个递归子函数遍历字典在每个节点上进行处理,当一个节点不支持类型时抛出一个TypeError,当一个值已经存在时抛出一个KeyError。
我想做的是对整个字典进行处理,忽略这些异常并最终处理它们,这样我就可以给出每个有问题的值的路径。如果没有引发异常,我想保存扁平字典。
如果我在try中包装对flatten_dict的调用...除了块之外,只会引发第一个异常,这会使所有有问题的值变得乏味。我考虑过使用日志记录,但后来我不知道如何让函数在结尾处引发异常,以便我可以采取相应的行动。
我想知道是否有办法做到这一点,或者如果它是一个标志我应该改变我的设计?
由于
def flatten_dict(dictionary):
"""
Flattens a dictionary to get the path to each value in the dict in dpath format (https://pypi.python.org/pypi/dpath/)
Returns a dict of the form "value":"path"
param: dictionary: the dictionary to be flattened, should contain each value only once, and all values should be strings
>>> reverse_flatten_dict({"k1":{"k2":"v2", "k3":["v3","v4"]}})
{"v2":"k1/k2","v3":"k1/k3/0","v4":"k1/k3/1"}
"""
def recursive_call(value, path, flattened):
"""
Recursively traverse the dictionary to add the path to each string \
value it encounters to the flattened dict
"""
if isinstance(value, dict):
for key, val in value.items():
new_path = "{}/{}".format(path,key)
recursive_call(val, new_path, flattened)
elif isinstance(value, list):
for i, val in enumerate(value):
new_path = "{}/{}".format(path,i)
recursive_call(val, new_path, flattened)
elif isinstance(value, basestring):
if value in flattened:
raise KeyError("flatten_dict: The value at {} is present more \
than once in the dictionary".format(path))
flattened[value] = path
else:
raise TypeError("flatten_dict: Value of invalid type at {},\
value ignored. Should be dict, list or basestring".format(path))
path = ""
flattened = {}
if dictionary:
recursive_call(dictionary, path, flattened)
return flattened
答案 0 :(得分:1)
可能有更好的方法,但最简单的方法是使用最少的代码调整来创建一个空列表,在if dictionary:
之上创建一个空列表,将它传递给递归函数,然后向它附加任何消息。然后在最后检查是否有任何并将它们作为一个例外。
示例代码:(注意:我使用的是Python 3,所以我无法测试这些确切的代码。我添加的所有部分应工作,其余部分从你的帖子,所以它也应该有用。)
def flatten_dict(dictionary):
"""
Flattens a dictionary to get the path to each value in the dict in dpath format (https://pypi.python.org/pypi/dpath/)
Returns a dict of the form "value":"path"
param: dictionary: the dictionary to be flattened, should contain each value only once, and all values should be strings
>>> reverse_flatten_dict({"k1":{"k2":"v2", "k3":["v3","v4"]}})
{"v2":"k1/k2","v3":"k1/k3/0","v4":"k1/k3/1"}
"""
def recursive_call(value, path, flattened, error_list):
"""
Recursively traverse the dictionary to add the path to each string \
value it encounters to the flattened dict
"""
if isinstance(value, dict):
for key, val in value.items():
new_path = "{}/{}".format(path,key)
recursive_call(val, new_path, flattened, error_list)
elif isinstance(value, list):
for i, val in enumerate(value):
new_path = "{}/{}".format(path,i)
recursive_call(val, new_path, flattened, error_list)
elif isinstance(value, basestring):
if value in flattened:
error_list.append("flatten_dict: The value at {} is present more \
than once in the dictionary".format(path))
flattened[value] = path
else:
error_list.append("flatten_dict: Value of invalid type at {},\
value ignored. Should be dict, list or basestring".format(path))
path = ""
flattened = {}
error_list = []
if dictionary:
recursive_call(dictionary, path, flattened, error_list)
if error_list:
# There was at least one error.
error_list = ["Errors encountered while flattening:"] + error_list
raise Exception('\n\t'.join(error_list))
return flattened
请注意,我不太喜欢这种解决方案,因为您会丢失确切的错误类型,并且不会在错误发生时引发错误。某些日志记录或指示所需行为的标志(忽略/日志/异常)可能更可取,具体取决于您的应用程序以及谁将使用它。