2013-03-08 64 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的版本非常合适,但可能需要在创建一些初始实例之后的某个时刻追加一个项目或扩展多个项目。