【问题标题】:Remember exceptions raised to handle them later记住引发的异常以便以后处理它们
【发布时间】:2017-07-25 09:58:17
【问题描述】:

TLDR:我想让一个函数运行某些异常,在最后显示它们并使函数引发异常。

我正在构建一个函数(见下文),通过创建“值”:“路径”形式的字典来获取字典中每个值的路径。我有一个递归子函数遍历字典在每个节点上进行处理,当节点不属于支持的类型时抛出 TypeError,当值已经存在时抛出 KeyError。

我想做的是对整个字典进行处理,忽略这些异常并仅在最后处理它们,这样我就可以为每个有问题的值提供路径。如果没有引发异常,我想保存扁平化的字典。

就目前而言,如果我在 try...except 块中包装对 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

【问题讨论】:

    标签: python exception logging exception-handling


    【解决方案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
    

    请注意,我不太喜欢这种解决方案,因为您会丢失确切的错误类型,并且不会在发生错误的地方引发错误。某种日志记录或指示所需行为的标志(忽略/日志/异常)可能更可取,具体取决于您的应用程序和谁将使用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-29
      • 1970-01-01
      • 2010-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-28
      相关资源
      最近更新 更多