我想动态更新类的属性,但似乎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方法,但如果可能的话,我想压缩它。
有人能给我解释一下为什么这个不起作用吗?我还能有什么选择?
谢谢你的帮忙
发布于 2013-03-08 19:37:26
您正在追加到就地列表。与所有就地变异函数一样,.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切片到values来创建len(values)的副本,而不需要循环。
如果您想要做的就是创建一个提供键和值作为属性的对象(很像dict使用属性访问而不是项访问),您还可以使用:
class Container(object):
def __init__(self, names, values):
self.__dict__.update(zip(names, values))然后运行:
Container(attributes, values)这消除了在循环中调用setattr()的需要。
发布于 2013-03-08 19:51:48
如果你能观察每一步的进度,它可能会帮助你理解正在发生的事情:
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中的原始列表(正如Martijn所指出的):
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的版本是非常合适的,但也许你必须在创建一些初始container实例之后的某个时刻附加一个项目,或者扩展多个项目。
https://stackoverflow.com/questions/15293006
复制相似问题