2013-03-08 62 views
1

我想動態地更新類的屬性,但似乎setattr和getattr的組合不起作用,因爲我想使用它。python combined setattr和getattr

這裏是我的主類:

class Container(object): 
    def __init__(self): 
     pass 
container = Container() 
attributes = ['a', 'b', 'c', 'd'] 
values = [[1, 2, 3, 4, 5], [True, False], ['red', 'blue', 'green'], [0, 1, -1, -5, 99]] 

請注意,這個例子我明確構造的屬性和它們各自的值的列表的目的。但是,在這個代碼的實際應用中,我什麼都沒有提前知道。他們的號碼,姓名或價值都不是。這需要動態地做到這一點。

這裏是代碼的其餘部分:

for key, value in zip(attributes, values): 
    setattr(container, key, []) 
    for val in value: 
     setattr(container, key, getattr(container, key).append(val)) 

當我運行這部分代碼不能正常工作。我可以將getattr部分保存在一個tmp變量中,然後在調用setattr之前調用列表的append方法,但如果可能的話,我想濃縮它。

任何人都可以解釋爲什麼這不起作用?我有什麼替代方案?

感謝您的幫助

+0

「*此部分在我運行代碼時不起作用*」如何?另外,你希望發生什麼? – Blender 2013-03-08 11:33:55

回答

3

您正在追加到列表中。像所有的就地突變功能,.append()回報None,讓你的最後一行:

setattr(container, key, getattr(container, key).append(val)) 

最終計算結果爲:

setattr(container, key, None) 

只需設置列表的副本的類:

for key, value in zip(attributes, values): 
    setattr(container, key, values[:]) 

其中[:]通過從0到len(values)創建一個values的副本在一個簡短的記號需要循環。

如果你想要做的就是創建一個對象,它提供鍵和值的屬性(很像dict將尚未與屬性訪問,而不是項目的訪問),你也可以使用:

class Container(object): 
    def __init__(self, names, values): 
     self.__dict__.update(zip(names, values)) 

然後運行:

Container(attributes, values) 

它不需要在循環中調用setattr()

+0

我在想'defaultdict(list)'是一個合適的人選...... – 2013-03-08 11:41:38

+0

謝謝你的澄清。你知道爲什麼getattr(容器,鍵,值)似乎與setattr(容器,鍵,值)一樣工作(一旦該屬性先前已經設置一次)? – user1713952 2013-03-08 11:42:30

+0

@ user1713952:它是'getattr(容器,鍵,默認)';如果'container'屬性沒有在'container'上設置,則返回'default'。既然你已經設置了*,'key','getattr(容器,鍵)'就足夠了。 – 2013-03-08 11:43:27

1

它可以幫助您瞭解發生了什麼事情,如果你可以觀看每一步的進展:

class Container(object): 
    def __init__(self): 
     pass 
    def __str__(self): 
     return '%s(%s)' % (self.__class__.__name__, 
      ', '.join(['%s = %s' % (attr, getattr(self, attr)) 
       for attr in self.__dict__])) 

現在你可以print container。如果你這樣做的嵌套循環,你會看到第一次嘗試setattr後你打一頓存儲在container.a原始列表(如馬亭指出):

for key, value in zip(attributes, values): 
    setattr(container, key, []) 
    for val in value: 
     print 'before:', container 
     setattr(container, key, getattr(container, key).append(val)) 
     print 'after:', container 

before: Container(a = []) 
after: Container(a = None) 
before: Container(a = None) 
Traceback (most recent call last): ... 

「最好」的方式做到這一點顯然取決於真正的問題 - 鑑於Martijn的版本非常合適,但可能需要在創建一些初始實例之後的某個時刻追加一個項目或擴展多個項目。