2011-12-21 34 views
0

我难以理解如何构建一个函数,它可以从内部列表中对列表中的列表进行操作(我想这就是您如何描述它的方式)。从Python中的列表中构建函数列表

我试图动态打开列表像

res = SomeDjangoQuerySet 
x = ['neighborhood', ['city', ['metro', 'metro']]] 

到:

getattr(getattr(getattr(getattr(res, 'neighborhood'), 'city'), 'metro'), 'metro') 

又名:

getattr(getattr(getattr(getattr(res, x[0]), x[1][0]), x[1][1][0]), x[1][1][1]) 

基本上,第一个值将始终是一个字符串,第二个值将是一个字符串或一个列表。每个列表将遵循此模式(字符串,字符串或列表)。列表内的列表深度不确定。 getattr()的最里面的第一个值将是一个外部变量(在这种情况下为'res')。有什么建议?

回答

3

这听起来像递归和迭代可能是有用的。这是否做你想要的?

def flatten(data): 
    res = [] 
    if hasattr(data, '__iter__'): 
     for el in data: 
      res.extend(flatten(el)) 
    else: 
     res.append(data) 
    return res 


reduce(getattr, flatten(x), res) 
+0

递归肯定是关键。这确实有效,但我发现这有点难以遵循,我最终想出了另一种方法(但谢谢你的回复都是一样的!) – alukach 2011-12-22 02:02:23

+0

经过第二次审视之后,这绝对会更好。我在这里学到了一些很酷的东西(hasattr()和reduce())。谢谢。 – alukach 2011-12-22 21:41:28

1
def nestattr(x, y): 
    if isinstance(y, str): 
     return getattr(x, y) 
    elif isinstance(y, list): 
     return nestattr(getattr(x, y[0]), y[1]) 

nestattr(res, x) 

所以你在列表中的第一个字符串开始,你必须(1)和(2)该字符串查询的getattr。然后你使用该列表的其余部分进行递归,如果它是一个字符串,你只需在(1)前getattr的结果getattr和(2)该字符串。否则,如果它仍然是一个列表,请重复。我认为这是你要找的东西?如我错了请纠正我。

+0

我认为这个版本会崩溃,如果你到达列表的末尾,那么一个空列表将被送入该函数,抛出'y [0]'的异常。 – 2011-12-21 09:32:59

+0

这不适合我,我得到一个'TypeError:getattr():属性名称必须是字符串',当它在结尾处击中y [0]。 – alukach 2011-12-22 02:04:10

+0

哎呦,我想在y [1:]里没有必要使用那个冒号。不需要切片。看来你已经找到了你的解决方案,但无论如何我都会进行更正。 – 2011-12-22 04:29:39

1

我最终花费了一些时间并学习了递归,并发现这是最简单的解决方案(虽然也赞扬David Zwicker也提供了一个工作解决方案)。

def recursion(a, b): 
    if type(b) is list: 
     return recursion(getattr(a, b[0]), b[1]) 
    else: 
     return getattr(a, b) 

recursion(res, x) 
+0

只有列表中有两个元素,您的版本才有效!如果你知道这总是如此,那当然是合法的,但重要的是要注意!另外,如果有一个列表嵌套在另一个列表的第一个位置,那么你的方法不能完全工作。 – 2011-12-22 08:21:19