问题: 我想知道最先进的方法是递归地将函数应用于对象中的字符串值,而不事先知道它的模式?优选地,以通用的方式使其成为用于其他类型操作的可重用组件。
上下文 我正在处理一个json字符串作为来自api请求的输入,使用json.loads()加载它,在应用验证之前,我想在对象中的任何字符串之前或之后去掉任何空格。我希望这段代码具有自适应性,以便架构中的更改不会破坏它。
当前解决方案:
def strip(obj):
return obj.strip()
def recurse_into(obj, baseaction, basetype=str):
if isinstance(obj, basetype):
return baseaction(obj)
elif isinstance(obj, list):
return [recurse_into(o, baseaction, basetype) for o in obj]
elif isinstance(obj, tuple):
return tuple(recurse_into(o, baseaction, basetype) for o in obj)
elif isinstance(obj, dict):
return dict((k, recurse_into(v, baseaction, basetype))
for (k, v) in obj.items())
else:
return obj
def generate_recurse(baseaction, basetype=str):
def f(obj):
return recurse_into(obj, baseaction, basetype)
return f
def recursive_strip_whitespace(obj):
clean_whitespace = generate_recurse(strip)
return clean_whitespace(obj)
当前解决方案的问题: 它看起来非常简洁,很难理解那些没有写它的人会发生什么,我真的希望有更可读的方法来做到这一点。或者这是否真的是最好的?
答案 0 :(得分:0)
我的建议是减少一些冗余代码:
def strip(obj):
return obj.strip()
def recurse_into(obj, baseaction, basetype=str):
if isinstance(obj, basetype):
return baseaction(obj)
elif isinstance(obj, list):
return [recurse_into(o, baseaction, basetype) for o in obj]
elif isinstance(obj, tuple):
return tuple(recurse_into(o, baseaction, basetype) for o in obj)
elif isinstance(obj, dict):
return dict((k, recurse_into(v, baseaction, basetype))
for (k, v) in obj.items())
return obj
def recursive_strip_whitespace(obj):
return recurse_into(obj, strip)
答案 1 :(得分:0)
同样的方法"逆转"将案例拆分为单独的函数并将其映射出来。它的变形性较小,但可能看起来更具可读性。
def strip_obj(obj):
return obj.strip()
def strip_tuple(tuple):
return tuple(recurse(obj) for obj in tupl)
...
def recurse(root):
actions = {basetype: strip_obj,
tuple: strip_tuple,
...}
return actions[type(root)](root)
请注意,对于iterables,你可以"去功能"与map
,但我个人觉得它太密集了。同样,您可以在lambda
个actions
值中使用{{1}}来恢复您的meta-juju,但同样对于可读性而言也不会很好。
答案 2 :(得分:0)
这是一个更简单、更优雅的解决方案,它保留了嵌套列表的内部类型结构:
def isiter(x):
return hasattr(x, '__iter__') and not isinstance(x, (str, bytes))
def apply_recursively(x, func, args=[], kwargs={}):
if not isiter(x):
return func(x, *args, **kwargs)
else:
ls_type = type(x)
ls = [apply_recursively(item, func, args, kwargs) for item in x]
return ls_type(ls)
例如:
>>> a = ['1', '2', '34', ('5', '67', ['8','10'])]
>>> apply_recursively(a, int)
[1, 2, 34, (5, 67, [8, 10])]
>>> b = ['forest', 'mountain', ('grass', 'cow', ['leaf','spider'])]
>>> apply_recursively(b, (lambda s, x: s+x), ['_thing'])
['forest_thing', 'mountain_thing',
('grass_thing', 'cow_thing', 'leaf_thing', 'spider_thing'])]