过滤一个变量,使其repr可以被literal_eval解析

时间:2014-05-05 13:14:32

标签: python serialization

我想过滤变量(即删除无效内容),以便ast.literal_eval可以解析其字符串表示形式。所以基本上是一个filter_literal函数,可以保证任何obj的以下断言:

safe_obj = filter_literal(obj)
assert ast.literal_eval(repr(safe_obj))==safe_obj

我提出了以下功能,但我感兴趣的是有更好的方法,否则,如果我做错了什么:

_literal_types = set([type(None),bool,int,float,long,complex])
def filter_literal(obj, default=None):
    """ return given `obj` with only "literal" types

    The output can be safely converted to string and evaluated using 
    `ast.literal_eval`::

        import ast
        safe_obj = filter_literal(obj)
        assert ast.literal_eval(repr(obj))==safe_obj

    literal types are strings, number, tuples, lists, dicts, booleans and None

    non-literal content are replaced by `default`
    """
    obj_type = type(obj)
    if obj_type in _literal_types:
        return obj
    elif isinstance(obj,dict):
        return dict((k,filter_literal(v,default=default)) for k,v in obj.iteritems())
    elif isinstance(obj,list):
        return [filter_literal(v,default=default) for v in obj]
    elif isinstance(obj,tuple):
        return tuple([filter_literal(v,default=default) for v in obj])
    else:
        return default

1 个答案:

答案 0 :(得分:1)

一个明显的错误是你没有处理不是字典键的字符串:

>>> test = {"bar": [1, True, None, "foo"]}
>>> filter_literal(test)
{'bar': [1, True, None, None]}

你应该添加:

if isinstance(obj, basestring):
    return obj

在决定你是否做错了什么的时候,测试你的功能

for test in [{"bar": [1, True, None, "foo"]}, ...]:
    assert ast.literal_eval(repr(filter_literal(test))) == test

定义一些测试并在进行更改时运行它。 另请注意,您可以简化递归调用,例如:

filter_literal(v, default)

我会在函数中移动_literal_types

def filter_literal(obj, default=None):
     """docstring."""
    _literal_types = set([type(None), bool, int, float, long, complex])
    ...