Python combining setattr and getattr
我想动态地更新类的属性,但似乎setattr和getattr的组合并不能像我想使用的那样工作。
这是我的主要课程:
1 2 3 4 5 6 | 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]] |
请注意,为了这个示例的目的,我显式地构造了属性列表及其各自的值。然而,在这个代码的实际应用中,我并没有提前知道任何事情。它们的数字、名称或值都不是。这就需要动态地进行。
下面是代码的其余部分:
1 2 3 4 | 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方法,但如果可能的话,我想对其进行压缩。
有人能解释我为什么这不起作用吗?我还有什么选择?
谢谢你的帮助
您正在将添加到适当的列表中。像所有的就地突变函数一样,
1 | setattr(container, key, getattr(container, key).append(val)) |
最终评估为:
1 | setattr(container, key, None) |
号
只需在类上设置列表的副本:
1 2 | for key, value in zip(attributes, values): setattr(container, key, values[:]) |
其中,
如果您只想创建一个提供键和值作为属性的对象(就像
1 2 3 | class Container(object): def __init__(self, names, values): self.__dict__.update(zip(names, values)) |
。
然后运行:
1 | Container(attributes, values) |
这样就不需要在循环中调用
如果你能观察每一步的进展,它可能会帮助你理解正在发生的事情:
1 2 3 4 5 6 7 | 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__])) |
。
现在你可以开始了。如果您在嵌套循环中这样做,您将看到在第一次尝试
1 2 3 4 5 6 7 8 9 10 11 | 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的版本非常合适,但是在创建一些初始