2011-12-21 30 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